且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

为什么Func键< T>暧昧与Func键<&IEnumerable的LT; T>&GT ;?

更新时间:2022-05-05 15:39:04

确定,这里的交易。​​

OK, here's the deal.

短的版本:


  • 含糊不清的错误是,奇怪的是足够的,正确的。

  • 的C#编译器4也正确的模糊性错误后产生一个虚假的错误。这似乎是在编译器中的错误。

长的版本:

我们有一个重载的问题。超载分辨率非常好规定。

We have an overload resolution problem. Overload resolution is extremely well specified.

步骤之一:确定所述候选集。这很容易。候选人是美孚(Func键< IEnumerable的<弦乐>>)美孚(Func键<弦乐>)。

Step one: determine the candidate set. That's easy. The candidates are Foo(Func<IEnumerable<String>>) and Foo(Func<String>).

步骤二:确定所述候选集的成员的适用的。适用的成员都有每个参数转换为每个参数的类型。

Step two: determine which members of the candidate set are applicable. An applicable member has every argument convertible to every parameter type.

美孚(Func键&LT;&IEnumerable的LT;弦乐&GT;&GT;)适用?那么,是 X 转换为 Func键&LT;&IEnumerable的LT;弦乐&GT;

Is Foo(Func<IEnumerable<String>>) applicable? Well, is X convertible to Func<IEnumerable<String>?

我们咨询规范的第6.6节。该规范的这一部分是我们语言的设计者称之为很奇怪。基本上,它说的转换可以存在,但使用的转换是一个错误的。 (还有为什么我们有这样奇怪的情况很好的理由,大多是具有避免未来的重大更改,避免鸡和蛋的情况下做的,但在你的情况下,我们正变得有些不幸的行为造成的。)

We consult section 6.6 of the spec. This part of the specification is what we language designers call "really weird". Basically, it says that a conversion can exist, but using that conversion is an error. (There are good reasons why we have this bizarre situation, mostly having to do with avoiding future breaking changes and avoiding "chicken and egg" situations, but in your case we are getting somewhat unfortunate behaviour as a result.)

基本上,这里的规则是从X到委托类型转换不带参数的存在的如果在表格的呼叫重载解析X()会成功。显然,这样的调用的将会的成功,因此转换存在。其实使用的是转换一个错误,因为返回类型不匹配,但是的重载总是忽略返回类型的。

Basically, the rule here is that a conversion from X to a delegate type with no parameters exists if overload resolution on a call of the form X() would succeed. Clearly such a call would succeed, and therefore a conversion exists. Actually using that conversion is an error because the return types don't match, but overload resolution always ignores return types.

所以,转化率从 X 存在 Func键&LT; IEnumerable的&LT;弦乐&GT; ,因此该超载是一个适用的人选。

So, a conversion exists from X to Func<IEnumerable<String>, and therefore that overload is an applicable candidate.

显然,对于相同的原因的其他过载也是适用的候选

Obviously for the same reason the other overload is also an applicable candidate.

第三步:我们现在有两个候选人适用。哪一个是更好?

Step Three: We now have two applicable candidates. Which one is "better"?

一来就是更好是一个具有的更具体的的类型。如果你有两个适用的候选人, M(动物) M(长颈鹿)我们选择了长颈鹿的版本,因为长颈鹿是比动物更具体。我们知道,长颈鹿是更具体的,因为每一个长颈鹿是动物,但不是每一种动物是长颈鹿。

The one that is "better" is the one with the more specific type. If you have two applicable candidates, M(Animal) and M(Giraffe) we choose the Giraffe version because a Giraffe is more specific than an Animal. We know that Giraffe is more specific because every Giraffe is an Animal, but not every Animal is a Giraffe.

不过你的情况也不类型是比其他更具体。有两种类型的函数功能之间没有转换。

But in your case neither type is more specific than the other. There is no conversion between the two Func types.

因此​​两者都不是好,所以重载解析报告错误。

Therefore neither is better, so overload resolution reports an error.

在C#编译器4遂将这似乎是一个bug,在它的错误恢复模式挑选候选人之一反正,和报告的其他的错误。目前尚不清楚对我来说这是为什么发生。基本上,它是说,错误恢复是选择了IEnumerable超载,然后注意到方法组转换产生的结果站不住脚;即,该字符串不兼容的IEnumerable&LT;弦乐方式&gt;

The C# 4 compiler then has what appears to be a bug, where its error recovery mode picks one of the candidates anyways, and reports another error. It's not clear to me why that is happening. Basically it is saying that error recovery is choosing the IEnumerable overload, and then noting that the method group conversion produces an untenable result; namely, that string is not compatible with IEnumerable<String>.

整个形势是相当不幸的;它可能已经不如说是没有方法,组到委托的转换,如果返回类型不匹配。 (或者说产生一个错误转换总是比不转换变得更糟。)但是,我们现在坚持了下来。

The whole situation is rather unfortunate; it might have been better to say that there is no method-group-to-delegate conversion if the return types do not match. (Or, that a conversion that produces an error is always worse than a conversion that does not.) However, we're stuck with it now.

一个有趣的事实:对于lambda表达式转换规则的的考虑返回类型。如果你说美孚(()=&GT; X())然后我们做了正确的事情。即lambda表达式和方法组有不同的兑换规则的事实是相当不幸的。

An interesting fact: the conversion rules for lambdas do take into account return types. If you say Foo(()=>X()) then we do the right thing. The fact that lambdas and method groups have different convertibility rules is rather unfortunate.

所以,总结,编译器实际上是一个正确实施这种情况下,规范的,而这个特定的场景是一些可以说是不幸的规格选择一个意想不到的后果。

So, summing up, the compiler is actually a correct implementation of the spec in this case, and this particular scenario is an unintended consequence of some arguably unfortunate spec choices.