通用扩展方法:无法从用法推断类型参数
我正在尝试创建一个适用于类型化数据表的通用扩展方法:
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 的原因是 'Expression<
Func<
T, bool>>
' 将由 InteliSence 键入并查看。
谢谢
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
方法类型推断不会从参数进行推断约束。它从参数到形式参数进行推论,然后检查从参数到形式参数的推论是否满足约束。
在您的情况下,如果不首先查看约束,则参数中没有足够的数据来推断出类型参数是什么,在我们检查针对约束的推论之前,我们不会这样做。对此感到抱歉,但这就是类型推断算法的指定方式。
我多次被问到这个问题,共识似乎是,我坚持推理应该仅从形式参数的论证中推断的立场在道德上是错误的。对于大约十几个人告诉我我在这方面是错误的,请参阅我对这个密切相关问题的分析的评论:
http://blogs.msdn.com/b/ericlippert/archive/2009/12/10/constraints- are-not-part-of-the-signature.aspx
我维持我的立场。
Method type inference does not make inferences from arguments to constraints. It makes inferences from arguments to formal parameters and then checks whether the inferences made from the arguments to the formals satisfy the constraints.
In your case there is not enough data from the arguments to deduce what the type parameters are without first looking at the constraints, which we're not going to do until we check the inferences against the constraints. Sorry about that, but that's how the type inference algorithm is specified.
I've been asked questions about this many times and the consensus seems to be that I am morally wrong for maintaining the position that inference should infer from arguments to formal parameters alone. For about a dozen people telling me I'm wrongheaded in this regard, see the comments to my analysis of this closely related issue:
http://blogs.msdn.com/b/ericlippert/archive/2009/12/10/constraints-are-not-part-of-the-signature.aspx
I maintain my position.
埃里克的回答很好地解释了为什么无法推断类型。这里有一些建议,希望可以减少您必须编写的代码的冗长性。
如果您可以显式定义 lambda 表达式的类型,那么它就可以推断出类型。
下面是如何执行此操作的一个示例。我创建了一个显式类型为
Expression>
的criteria
参数。在这个例子中,这并不能节省你太多的打字时间,但也许在实践中你可以利用它。编辑:更改我的示例以使用另一种扩展方法,而不是从
System.Data.TypedTableBase
派生自定义TypedTableBase
类。下面是另一个可以更好地推断类型参数的示例。您定义了另一种扩展方法(我的称为
RowPredicate
),它只有一个类型参数可供推断。第一个参数的类型为TypedTableBase
,因此编译器从中推断类型应该没有问题:这允许您编译以下代码:
主要是
table
参数只是通知编译器用于RowType
的类型。这是个好主意吗?我不太确定,但它确实允许编译器推断所有泛型类型。Eric's answer is great for explaining why the types cannot be inferred. Here are a couple of suggestions to hopefully cut down on the verbosity of the code that you will have to write.
If you can explicitly define the type of your lambda expression, then it can infer the types.
One example of how to do that is below. I've created a
criteria
parameter that is explicitly of typeExpression<Func<MyTypedDataSet.MyTypedRow, bool>>
. In this example, this doesn't save you much typing, but perhaps in practice you can make use of this.EDIT: altered my example to use another extension method rather than deriving a custom
TypedTableBase<T>
class fromSystem.Data.TypedTableBase<T>
.Below is another example that can do a better job of inferring the type parameters. You define another extension method (mine is called
RowPredicate
) that only has one type parameter to infer. The first parameter is of typeTypedTableBase<RowType>
, so the compiler should have no problem inferring the type from that:This allows you to compile the following code:
Primarily the
table
parameter simply servers to inform the compiler of the type to use forRowType
. Is this a good idea? I'm not so sure, but it does allow the compiler to infer all of the generic types.即使这并不理想,我也放弃了尝试返回任何允许我执行如下操作的内容:
然后像这样使用它:
并且编译器会正确推断类型。
谢谢两位的回答。
Even if that wasn't ideal, I gave up trying to return anything at all which allows me to do something like the following:
And then use it like so:
and the compiler infers the type correctly.
Thank you both for your answers.