鉴于此代码:
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 _) { }
}
Run Code Online (Sandbox Code Playgroud)
编译器抱怨Test(A)
无法弄清楚T
是string
.
这对我来说似乎是一个非常简单的案例,我发誓我在其他通用实用程序和扩展函数中依赖于更复杂的推理.我在这里错过了什么?
更新1:这是在C#4.0编译器中.我在VS2010中发现了这个问题,上面的示例来自我在LINQPad 4中制作的最简单的repro.
更新2:在可用的列表中添加了更多示例.
Jef*_*dge 35
Test(A);
Run Code Online (Sandbox Code Playgroud)
这失败是因为唯一适用的方法(Test<T>(Action<T>)
)需要类型推断,并且类型推断算法要求每个参数都是某种类型或者是匿名函数.(这个事实是从类型推断算法(第7.5.2节)的规范推断出来的)方法组A
不是任何类型的(即使它可以转换为适当的委托类型),并且它不是匿名函数.
Test<string>(A);
Run Code Online (Sandbox Code Playgroud)
这成功了,区别在于类型推断不是绑定Test所必需的,方法组A可以转换为所需的委托参数类型void Action<string>(string)
.
Test((string a) => {});
Run Code Online (Sandbox Code Playgroud)
这成功了,不同之处在于类型推断算法在第一阶段(第7.5.2.1节)中提供了匿名函数.参数和返回类型匿名函数是已知的,所以显式参数类型推断可以被做,和一个correspondense在匿名函数(各类型之间从而制成void ?(string)
)和委托类型的类型参数Test
方法的参数(void Action<T>(T)
).没有为与匿名函数的此算法对应的方法组指定算法.
Test((Action<string>)A);
Run Code Online (Sandbox Code Playgroud)
这成功了,不同之处在于将无类型方法组参数A
强制转换为类型,从而允许类型推断Test
通常使用特定类型的表达式作为方法的唯一参数.
理论上我没理由为什么不能在方法组上尝试重载解析A
.然后 - 如果找到单个最佳绑定 - 方法组可以被赋予与匿名函数相同的处理.在这样的情况下尤其如此,其中方法组恰好包含一个候选项并且它没有类型参数.但它在C#4中不起作用的原因似乎是这个功能没有设计和实现.鉴于此功能的复杂性,应用程序的狭隘性以及三种简单解决方案的存在,我不会为此屏住呼吸!
我认为这是因为这是一个两步推理:
它必须推断您要将A转换为通用委托
它必须推断委托参数的类型应该是什么
我不确定这是否是原因,但我的预感是,对于编译器来说,两步推理并不一定容易.
只是预感,但有些东西告诉我第一步是问题.编译器必须计算转换为具有不同数量的泛型参数的委托,因此它无法推断参数的类型.
这看起来像是一个恶性循环.
Test
method期望从泛型类型构造的委托类型的参数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);
Run Code Online (Sandbox Code Playgroud)
或显式指定type参数:
Test<string>(A); // compiler knows what type of delegate to convert A to
Run Code Online (Sandbox Code Playgroud)
PS 更多关于类型推断