为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C#
噜噜哒 2019-10-19 16:16:08
给出以下代码: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)无法弄清楚T是string。对我来说,这似乎是一个非常简单的案例,并且我发誓我已经对我编写的其他通用实用程序和扩展函数进行了更为复杂的推断。我在这里想念什么?更新1:这是在C#4.0编译器中。我在VS2010中发现了这个问题,上面的示例来自我在LINQPad 4中所做的最简单的复制。更新2:在有效列表中添加了更多示例。
查看完整描述

3 回答

?
慕侠2389804

TA贡献1719条经验 获得超6个赞

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中不起作用的原因似乎是没有设计和实现此功能的事实。鉴于此功能的复杂性,其应用的局限性以及三个简单的解决方法的存在,我不会为此而屏息!


查看完整回答
反对 回复 2019-10-19
?
慕田峪7331174

TA贡献1828条经验 获得超13个赞

我认为这是因为有两步推断:


它必须推断出您要将A转换为通用委托


它必须推断委托参数的类型是什么


我不确定这是否是原因,但我的直觉是两步推断对于编译器而言不一定很容易。


编辑:

只是预感,但是有什么告诉我第一步是问题。编译器必须弄清楚要转换为具有不同数量的泛型参数的委托,因此无法推断参数的类型。


查看完整回答
反对 回复 2019-10-19
?
幕布斯7119047

TA贡献1794条经验 获得超8个赞

在我看来,这似乎是一个恶性循环。


Test方法需要从泛型类型构造的委托类型参数Action<T>。您改为传入一个方法组:Test(A)。这意味着编译器必须将您的参数转换为委托类型(方法组转换)。


但是,哪种代表类型?要知道委托类型,我们需要知道T。我们没有明确指定它,因此编译器必须推断出它以找出委托类型。


要推断方法的类型参数,我们需要知道方法参数的类型,在这种情况下为委托类型。编译器不知道参数类型,因此失败。


在所有其他情况下,两种类型的参数都是显而易见的:


// delegate is created out of anonymous method,

// no method group conversion needed - compiler knows it's Action<string>

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


// type of argument is set explicitly

Test((Action<string>)A); 

或明确指定类型参数:


Test<string>(A); // compiler knows what type of delegate to convert A to


查看完整回答
反对 回复 2019-10-19
  • 3 回答
  • 0 关注
  • 584 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信