简体   繁体   English

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

[英]Generic extension method : Type argument cannot be inferred from the usage

I'm trying to create a generic extension method, that works on typed data tables :我正在尝试创建一个适用于类型化数据表的通用扩展方法:

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
    }
}

The first line works fine, but it's really ugly...第一行工作正常,但它真的很难看......
The second line doesn't compile because the compiler cannot infer the type of RowType .第二行不编译因为编译器不能推断ROWTYPE的类型。
This is a method that will be used as part of a DataLayer by many different programmers, so I would rather not need them to specify the TypeParameter.这是一种将被许多不同程序员用作 DataLayer 的一部分的方法,因此我宁愿不需要他们指定 TypeParameter。
Shouldn't the compiler know that RowType is the same type as the one that was used by TypedTableBase ?如果不是编译器知道ROWTYPE是同类型已使用的TypedTableBase的人吗?

For different reasons that may not be obvious in this code sample, I really need to return the datatable in its original form.由于在此代码示例中可能不明显的不同原因,我确实需要以原始形式返回数据表。 And the reason I need RowType is so the 'Expression < Func < T, bool> > ' will be typed and seen by InteliSence.我需要RowType的原因是'Expression < Func < T, bool> > ' 将被 InteliSence 输入和看到。

Thanks谢谢

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 http://blogs.msdn.com/b/ericlippert/archive/2009/12/10/constraints-are-not-part-of-the-signature.aspx

I maintain my position.我保持我的立场。

Eric's answer is great for explaining why the types cannot be inferred. Eric 的回答非常适合解释为什么不能推断类型。 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.如果您可以明确定义 lambda 表达式的类型,则它可以推断类型。

One example of how to do that is below.下面是如何做到这一点的一个示例。 I've created a criteria parameter that is explicitly of type Expression<Func<MyTypedDataSet.MyTypedRow, bool>> .我创建了一个明确类型为Expression<Func<MyTypedDataSet.MyTypedRow, bool>>criteria参数。 In this example, this doesn't save you much typing, but perhaps in practice you can make use of this.在此示例中,这不会为您节省太多输入,但也许在实践中您可以利用它。

        MyTypedDataSet.MyTypedDataTable table = new MyTypedDataSet.MyTypedDataTable();

        Expression<Func<MyTypedDataSet.MyTypedRow, bool>> criteria = row => row.Field1 == "foo";

        return table.DoSomething(criteria);

EDIT: altered my example to use another extension method rather than deriving a custom TypedTableBase<T> class from System.Data.TypedTableBase<T> .编辑:更改我的示例以使用另一种扩展方法,而不是从System.Data.TypedTableBase<T>派生自定义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.您定义了另一种扩展方法(我的称为RowPredicate ),它只有一个类型参数可供推断。 The first parameter is of type TypedTableBase<RowType> , so the compiler should have no problem inferring the type from that:第一个参数的类型为TypedTableBase<RowType> ,因此编译器从它推断类型应该没有问题:

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

This allows you to compile the following code:这允许您编译以下代码:

        MyTypedDataSet.MyTypedDataTable table = new MyTypedDataSet.MyTypedDataTable();

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

Primarily the table parameter simply servers to inform the compiler of the type to use for RowType .主要是table参数只是用于通知编译器要用于RowType的类型。 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:即使这并不理想,我也放弃了尝试返回任何允许我执行以下操作的任何内容:

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
    }

And then use it like so:然后像这样使用它:

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

and the compiler infers the type correctly.并且编译器正确推断类型。

Thank you both for your answers.谢谢你们的回答。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM