为什么可以';t C#从这个看似简单、显而易见的案例中推断类型
鉴于此代码:为什么可以';t C#从这个看似简单、显而易见的案例中推断类型,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
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 _) { }
}
C类
{
C()
{
测试(A);//好的
Test((字符串a)=>{});//很好
测试((动作)A);//好
Test(A);//无法从用法推断类型参数!
}
静态空隙试验(动作a){}
空A(字符串{}
}
编译器抱怨Test(A)
无法将t
理解为string
Test((string a) => {});
对我来说,这似乎是一个非常简单的例子,我发誓我在我编写的其他通用实用程序和扩展函数中依赖了更复杂的推理。我错过了什么
更新1:这在C#4.0编译器中。我在VS2010中发现了这个问题,上面的示例来自于我在LINQPad 4中制作的一个最简单的例子
更新2:在工作列表中添加了更多示例。我认为这是因为这是一个两步推理:
- 它必须推断您想要将代理转换为泛型委托
- 它必须推断委托参数的类型
编辑:
只是一种预感,但有些事情告诉我,第一步就是问题。编译器必须考虑转换为具有不同数量的泛型参数的委托,因此无法推断参数的类型。我认为这是因为这是一个两步推断:
- 它必须推断您想要将代理转换为泛型委托
- 它必须推断委托参数的类型
编辑:
只是一种预感,但有些事情告诉我,第一步就是问题。编译器必须找出如何转换为具有不同数量的泛型参数的委托,因此无法推断参数的类型。您传递的是方法的名称a。.Net framework可以将其转换为
操作
,但它是隐式的,不会对此负责
但是,方法名仍然不是显式的
操作
对象。因此,它不会将该类型推断为操作
类型。您正在传递方法的名称A。Net framework可以将其转换为操作
,但它是隐式的,不会对此负责
但是,方法名仍然不是显式的
操作
对象。因此,它不会将该类型推断为操作类型。在我看来,这似乎是一个恶性循环
Test
方法需要一个由泛型类型Action
构造的委托类型的参数。您通过的是方法组:测试(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);
//委托由匿名方法创建,
//不需要方法组转换-编译器知道它的操作
测试((字符串a)=>{});
//参数的类型是显式设置的
试验((动作)A);
或类型参数已明确指定:
Test<string>(A); // compiler knows what type of delegate to convert A to
测试(A);//编译器知道要将代理转换为哪种类型
另外,这在我看来是一个恶性循环
Test
方法需要一个由泛型类型Action
构造的委托类型的参数。您通过的是方法组:测试(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);
//委托由匿名方法创建,
//不需要方法组转换-编译器知道它的操作
测试((字符串a)=>{});
//参数的类型是显式设置的
试验((动作)A);
或类型参数已明确指定:
Test<string>(A); // compiler knows what type of delegate to convert A to
测试(A);//编译器知道要将代理转换为哪种类型
附言
这会失败,因为唯一适用的方法(Test(Action)
)需要类型推断,而类型推断算法要求每个参数都是某种类型或匿名函数。(根据类型推断算法规范(§7.5.2)推断出这一事实)方法组A
不是任何类型(即使它可以转换为适当的委托类型),并且它不是匿名函数
Test<string>(A);
这是成功的,不同之处在于类型推断算法在第一阶段(§7.5.2.1)中规定了匿名函数。匿名函数的参数和返回类型是已知的,因此可以进行显式的参数类型推断,从而在匿名函数中的类型(void?(string)
)和Test
方法参数的委托类型中的类型参数(void Action(T))之间建立对应关系
)。没有为对应的方法组指定算法