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

发布于 2024-09-16 17:51:04 字数 1474 浏览 4 评论 0 原文

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

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 键入并查看。

谢谢

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.
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.
Shouldn't the compiler know that RowType is the same type as the one that was used by 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.

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

死开点丶别碍眼 2024-09-23 17:51:04

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

在您的情况下,如果不首先查看约束,则参数中没有足够的数据来推断出类型参数是什么,在我们检查针对约束的推论之前,我们不会这样做。对此感到抱歉,但这就是类型推断算法的指定方式。

我多次被问到这个问题,共识似乎是,我坚持推理应该仅从形式参数的论证中推断的立场在道德上是错误的。对于大约十几个人告诉我我在这方面是错误的,请参阅我对这个密切相关问题的分析的评论:

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.

久光 2024-09-23 17:51:04

埃里克的回答很好地解释了为什么无法推断类型。这里有一些建议,希望可以减少您必须编写的代码的冗长性。

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

下面是如何执行此操作的一个示例。我创建了一个显式类型为 Expression>criteria 参数。在这个例子中,这并不能节省你太多的打字时间,但也许在实践中你可以利用它。

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

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

        return table.DoSomething(criteria);

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

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

    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参数只是通知编译器用于 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 type Expression<Func<MyTypedDataSet.MyTypedRow, bool>>. 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>.

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 type TypedTableBase<RowType>, so the compiler should have no problem inferring the type from that:

    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. Is this a good idea? I'm not so sure, but it does allow the compiler to infer all of the generic types.

哆啦不做梦 2024-09-23 17:51:04

即使这并不理想,我也放弃了尝试返回任何允许我执行如下操作的内容:

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"));

并且编译器会正确推断类型。

谢谢两位的回答。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文