简体   繁体   English

为什么匿名委托/ lambdas不在out / ref参数上推断类型?

[英]Why don't anonymous delegates/lambdas infer types on out/ref parameters?

Several C# questions on StackOverflow ask how to make anonymous delegates/lambdas with out or ref parameters. StackOverflow上的几个C#问题询问如何使用outref参数创建匿名委托/ lambdas。 See, for example: 例如,见:

To do so, you just need to specify the type of the parameter, as in: 为此,您只需指定参数的类型,如:

public void delegate D(out T p);
// ...
D a = (out T t) => { ... };      // Lambda syntax.
D b = delegate(out T t) { ... }; // Anonymous delegate syntax.

What I'm curious about is why the type is explicitly required. 我很好奇的是为什么明确要求类型。 Is there a particular reason that this is the case? 有这种情况的特殊原因吗? That is, from a compiler/language standpoint, why isn't the following allowed? 也就是说,从编译器/语言的角度来看,为什么不允许以下内容?

D a = (out t) => { ... };      // Lambda syntax -- implicit typing.
D b = delegate(out t) { ... }; // Anonymous delegate syntax -- implicit typing.

or even better, just: 甚至更好,只是:

D a = (t) => { ... };      // Lambda syntax -- implicit typing and ref|out-ness.
D b = delegate(t) { ... }; // Anonymous delegate syntax -- implicit typing and ref|out-ness.

Interesting question. 有趣的问题。

First, consider the difference between anonymous methods and lambdas. 首先,考虑匿名方法和lambdas之间的区别。 From the compiler writer's perspective, the most important difference is that lambdas can require the compiler to infer the type of the parameters from the target to which the lambda is being assigned; 从编译器编写者的角度来看,最重要的区别是lambdas可以要求编译器从lambda被分配到的目标中推断出参数的类型; C# 2 anonymous methods do not have this feature. C#2匿名方法没有此功能。 This feature seems like a small difference but in fact it has major ramifications on the implementation of the compiler. 这个功能看起来差别不大,但实际上它对编译器的实现有重大影响。 See my blog series on this topic for some thoughts on why that is: 请参阅我关于此主题的博客系列,了解其原因:

http://blogs.msdn.com/ericlippert/archive/2007/01/10/lambda-expressions-vs-anonymous-methods-part-one.aspx http://blogs.msdn.com/ericlippert/archive/2007/01/10/lambda-expressions-vs-anonymous-methods-part-one.aspx

So now let's come to your actual question: why can we not infer outness/refness from the target type to the parameters of the lambda. 那么现在让我们来看看你的实际问题:为什么我们不能从目标类型推断出lambda的参数中的outness / refness。 That is, if we have delegate void D(out int x) then surely D d = x=> { x = 10; 也就是说,如果我们有委托空D(out int x)那么肯定D d = x => {x = 10; } could infer that x is "out int". 可以推断x是“out int”。

There's no technical reason I'm aware of why we could not do that. 没有技术原因我知道为什么我们不能这样做。 Internally in the compiler the out/ref types are represented as types like any other. 在编译器内部,out / ref类型表示为类似于任何其他类型的类型。

However, features do not get done just because they can be done; 然而,功能不能仅仅因为它们可以完成而完成; they get done because there's a compelling reason to do so. 他们完成了,因为有一个令人信服的理由这样做。 For lambdas, the compelling reason to do type inference in the first place is LINQ; 对于lambdas,首先进行类型推断的令人信服的理由是LINQ; we want to be able to do a simple syntactic transformation on a query comprehension into a method call with lambdas, and let the method type inference engine work out the types of all the lambda parameters. 我们希望能够使用lambdas对查询理解进行简单的语法转换,并让方法类型推理引擎计算出所有lambda参数的类型。 None of the LINQ methods generated have delegates with out or ref parameters. 生成的LINQ方法都没有带有out或ref参数的委托。

So, we have no compelling reason to do the feature. 因此,我们没有令人信服的理由去做这个功能。 Delegates which have out/ref parameters are relatively rare. 具有out / ref参数的代表相对较少。 And assignment of lambdas to those delegates is rarer still. 而且,为那些代表分配lambda仍然是罕见的。 So this is a feature that we don't need, and that benefits almost no one. 所以这是我们不需要的功能,几乎没有人受益。

C# 3 was the "long pole" on the Visual Studio schedule; C#3是Visual Studio计划中的“长杆”; we had the most number of days of work scheduled of any team that ships a component in VS. 我们在VS中运送组件的任何团队安排了最多的工作日。 That meant that every day we slipped the schedule, the entire division slipped. 这意味着每天我们都按照时间表顺利进行,整个部门都下滑了。 That was a powerful disincentive to spending time on unnecessary features that benefitted no one. 这对于花费时间在不受益于任何人的不必要功能上具有强大的抑制作用。 So the work was never done. 所以这项工作从未完成。

I agree that it would be nice to be more consistent here, but it's unlikely to happen. 我同意在这里更加一致会很好,但不太可能发生。 We have many higher priorities. 我们有许多更优先的事项。

From Eric Lippert's comment on why declaration and assignment of a var variable cannot be split: 埃里克利珀的评论为什么一个声明和分配var变量不能被分割:

I agree that in principle this could be done, but it is rather more complicated in practice than your quick sketch would indicate. 我同意原则上可以这样做,但实际上它比你的快速草图所表明的要复杂得多。 var not only requires that there be an initializer, it also requires that the initializer not refer to the variable. var不仅要求有初始化器,还要求初始化器不引用变量。 If you have int M(out int) then you can say "int x = M(out x);" 如果你有int M(out int)那么你可以说“int x = M(out x);” but you cannot say "var x = M(out x);" 但你不能说“var x = M(out x);” because to do overload resolution on M, we need to know the type of x, which is what we're attempting to figure out. 因为要对M进行重载决策,我们需要知道x的类型,这是我们试图弄清楚的。 Would it be legal to say "var s; if (b) M(out s); else s = 0;" 说“var s; if(b)M(out s); s = 0;”是否合法 ?

I'd guess the answer to your question is similar, considering, for example, 我想你的问题的答案是相似的,例如,考虑到

D a = (out var x) => x = M(out x);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM