一尘不染

为什么C#无法从这种看似简单,明显的情况推断出类型

c#

给出以下代码:

class C
{
    C()
    {
        Test<string>(A); // fine
        Test((string a) => {}); // fine
        Test((Action<string>)A); // fine

        Test(A); // type arguments cannot be inferred from usage!
    }

    static void Test<T>(Action<T> a) { }

    void A(string _) { }
}

编译器抱怨Test(A)无法弄清楚Tstring

对我来说,这似乎是一个非常简单的案例,并且我发誓我已经对我编写的其他通用实用程序和扩展函数进行了更为复杂的推断。我在这里想念什么?

更新1:这是在C#4.0编译器中。我在VS2010中发现了这个问题,上面的示例来自我在LINQPad 4中所做的最简单的复制。

更新2:在有效列表中添加了更多示例。


阅读 256

收藏
2020-05-19

共1个答案

一尘不染

Test(A);

之所以失败,是因为唯一适用的方法(Test<T>(Action<T>))需要类型推断,并且类型推断算法要求每个每个参数都属于某种类型或为匿名函数。(从类型推断算法的规范(第7.5.2节)中推断出这一事实)方法组A不是任何类型(即使它可以转换为适当的委托类型),并且它不是匿名函数。

Test<string>(A);

这成功完成,区别在于绑定Test不需要类型推断,并且方法组A可转换为所需的委托参数type void Action<string>(string)

Test((string a) => {});

这样成功了,区别在于类型推断算法在第一阶段(第7.5.2.1节)提供了匿名函数。匿名函数的参数和返回类型是已知的,因此可以进行显式的参数类型推断,从而在匿名函数(void ?(string))中的类型与Test方法的参数的委托类型((void Action<T>(T))。没有为与匿名函数的算法相对应的方法组指定算法。

Test((Action<string>)A);

这成功完成,区别在于未类型化的方法组参数A被强制转换为类型,从而允许类型推断Test以特定类型的表达式作为方法的唯一参数正常进行。

从理论上讲,我无法认为为什么无法在方法组上尝试重载解析A。然后,如果找到单个最佳绑定,则可以为方法组提供与匿名函数相同的处理。在这样的情况下尤其如此,即方法组仅包含一个候选项,并且没有类型参数。但是它在C#4中不起作用的原因似乎是没有设计和实现此功能的事实。鉴于此功能的复杂性,其应用的局限性以及三个简单的解决方法的存在,我不会为此而屏息!

2020-05-19