通用扩展方法:无法从用法推断出类型参数

时间:2010-09-02 18:42:58

标签: c# database generics lambda

我正在尝试创建一个适用于类型化数据表的通用扩展方法:

public static class Extensions
{
    public static TableType DoSomething<TableType, RowType>(this TableType table, param Expression<Func<RowType, bool>>[] predicates)
        where TableType : TypedTableBase<RowType>
        where RowType : DataRow
    {
        // do something to each row of the table where the row matches the predicates
        return table;
    }

    [STAThread]
    public static void main()
    {
        MyTypedDataSet.MyTypedDataTable table = getDefaultTable();
    }

    public static MyTypedDataSet.MyTypedDataTable getDefaultTable()
    {
        // this line compiles fine and does what I want:
        return new MyTypedDataSet.MyTypedDataTable().DoSomething<MyTypedDataSet.MyTypedDataTable, MyTypedDataSet.MyTypedRow>(row => row.Field1 == "foo");

        // this line doesn't compile :
        return new MyTypedDataSet.MyTypedDataTable().DoSomething(row => row.Field1 == "foo");
        // Error : The type arguments .. cannot be inferred from the usage
    }
}

第一行工作正常,但它真的很难看...... 第二行无法编译,因为编译器无法推断 RowType 的类型 这是一种方法,将被许多不同的程序员用作DataLayer的一部分,所以我宁愿不需要它们来指定TypeParameter。
编译器是否应该知道 RowType 与TypedTableBase使用的类型相同?

由于在此代码示例中可能不明显的不同原因,我确实需要以原始形式返回数据表。我需要 RowType 的原因是“表达式< Func < T,bool&gt; >'将被InteliSence输入并查看。

由于

3 个答案:

答案 0 :(得分:22)

方法类型推断不会从约束的参数推断出来。它从形式参数的参数推断,然后检查从形式的参数做出的推断是否满足约束。

在你的情况下,没有足够的参数数据来推断出类型参数是什么而没有先查看约束,我们不会做直到我们检查对约束的推断。很抱歉,但这就是指定类型推断算法的方法。

我被问过很多次这样的问题,而且我的共识似乎是我在维持推理应该仅仅从形式参数的论证中推断的立场上是错误的。有十几个人告诉我,我在这方面有错误,请参阅我对这个密切相关问题的分析评论:

http://blogs.msdn.com/b/ericlippert/archive/2009/12/10/constraints-are-not-part-of-the-signature.aspx

我保持自己的立场。

答案 1 :(得分:0)

Eric的答案非常适合解释无法推断出类型的原因。以下是一些建议,希望能够减少您必须编写的代码的详细程度。

如果您可以明确定义lambda表达式的类型,那么它可以推断出类型。

如何做到这一点的一个例子如下。我创建了一个显式为criteria的{​​{1}}参数。在这个例子中,这不会为你节省太多的输入,但也许在实践中你可以使用它。

Expression<Func<MyTypedDataSet.MyTypedRow, bool>>

编辑:修改我的示例以使用其他扩展方法,而不是从 MyTypedDataSet.MyTypedDataTable table = new MyTypedDataSet.MyTypedDataTable(); Expression<Func<MyTypedDataSet.MyTypedRow, bool>> criteria = row => row.Field1 == "foo"; return table.DoSomething(criteria); 派生自定义TypedTableBase<T>类。

下面是另一个可以更好地推断类型参数的示例。您定义了另一个扩展方法(我的名为System.Data.TypedTableBase<T>),只有一个类型参数可以推断。第一个参数是RowPredicate类型,因此编译器应该没有问题从中推断出类型:

TypedTableBase<RowType>

这允许您编译以下代码:

    public static Expression<Func<RowType, bool>> RowPredicate<RowType>(this TypedTableBase<RowType> table, Expression<Func<RowType, bool>> predicate)
        where RowType : DataRow
    {
        return predicate;
    }

主要是 MyTypedDataSet.MyTypedDataTable table = new MyTypedDataSet.MyTypedDataTable(); return table.DoSomething(table.RowPredicate(row => row.Field1 == "foo")); 参数只是服务器通知编译器用于table的类型。这是一个好主意吗?我不太确定,但它确实允许编译器推断所有泛型类型。

答案 2 :(得分:0)

即使那不理想,我也放弃了试图返回任何东西,让我做出类似的事情:

public static void DoSomething<RowType>(this TypedTableBase<RowType> table, param Expression<Func<RowType, bool>>[] predicates)
    where RowType : DataRow
    {
        // do something to each row of the table where the row matches the predicates
        // do not return the table... too bad for chaining commands
    }

然后像这样使用它:

MyTypedDataSet.MyTypedDataTable table = new MyTypedDataSet.MyTypedDataTable();
table.DoSomething(row => row.Field1 == "foo"));

并且编译器正确地推断出类型......

感谢您的回答。

相关问题