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

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

public static class Extensions { public static TableType DoSomething(this TableType table, param Expression<Func>[] predicates) where TableType : TypedTableBase 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(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使用的类型相同?

由于在此代码示例中可能不明显的不同原因,我确实需要以原始forms返回数据表。 我需要RowType的原因是InteliSence会输入’Expression < Func < T,bool >>>’。

谢谢

方法类型推断不会从参数到约束进行推断。 它从forms参数的参数推断,然后检查从forms的参数得到的推断是否满足约束。

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

我多次被问到有关这方面的问题,而且我的共识似乎是因为我认为推理应该仅仅从forms参数的论证中推断出这一点,这在道德上是错误的。 有十几个人告诉我,我在这方面有错误,请参阅我对这个密切相关问题的分析评论:

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

我保持我的立场。

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

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

下面是如何做到这一点的一个例子。 我创建了一个criteria参数,显式类型为Expression> 。 在这个例子中,这不会为你节省太多的打字,但也许在实践中你可以使用它。

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

编辑:修改我的示例以使用另一个扩展方法,而不是从System.Data.TypedTableBase派生自定义TypedTableBase类。

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

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

这允许您编译以下代码:

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

主要是table参数服务器通知编译器用于RowType的类型。 这是一个好主意吗? 我不太确定,但它确实允许编译器推断所有generics类型。

即使那不理想,我也放弃了试图返回任何东西的女巫允许我做这样的事情:

 public static void DoSomething(this TypedTableBase table, param Expression>[] 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")); 

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

谢谢你们的回答。