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

时间:2010-01-02 04:20:24

标签: c# delegates lambda anonymous-methods out-parameters

StackOverflow上的几个C#问题询问如何使用outref参数创建匿名委托/ lambdas。例如,见:

为此,您只需指定参数的类型,如:

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

我很好奇的是为什么要明确要求这种类型。有这种情况的特殊原因吗?也就是说,从编译器/语言的角度来看,为什么不允许以下内容?

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

甚至更好,只是:

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

2 个答案:

答案 0 :(得分:17)

有趣的问题。

首先,考虑匿名方法和lambdas之间的区别。从编译器编写者的角度来看,最重要的区别是lambdas可以要求编译器从lambda被分配到的目标中推断出参数的类型; C#2匿名方法没有此功能。这个功能看起来差别不大,但实际上它对编译器的实现有重大影响。请参阅我关于此主题的博客系列,了解其原因:

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

现在让我们来看看你的实际问题:为什么我们不能从目标类型推断出lambda的参数中的outness / refness。也就是说,如果我们有委托空D(out int x)那么肯定D d = x => {x = 10;可以推断x是“out int”。

没有技术原因我知道为什么我们不能这样做。在编译器内部,out / ref类型表示为类似于任何其他类型的类型。

然而,功能不能仅仅因为它们可以完成;他们完成了,因为有一个令人信服的理由这样做。对于lambdas,首先进行类型推断的令人信服的理由是LINQ;我们希望能够使用lambdas对查询理解进行简单的语法转换,并让方法类型推理引擎计算出所有lambda参数的类型。 生成的所有LINQ方法都没有带有out或ref参数的委托。

因此,我们没有令人信服的理由去做这个功能。具有out / ref参数的代表相对较少。而且,为那些代表分配lambda仍然是罕见的。所以这是我们不需要的功能,几乎没有人受益。

C#3是Visual Studio计划中的“长杆”;我们在VS中运送组件的任何团队安排了最多的工作日。这意味着我们每天都按照时间表进行调整,整个部门下滑。这对于花费时间在不受益于任何人的不必要功能上具有强大的抑制作用。所以这项工作从未完成。

我同意在这里更加一致会很好,但不太可能发生。我们有许多更高的优先事项。

答案 1 :(得分:2)

Eric Lippert's comment开始,为什么不能分割var变量的声明和赋值:

  

我同意原则上可以这样做,但实际上它比你的快速草图所表明的要复杂得多。 var不仅要求有初始化器,还要求初始化器不引用变量。如果你有int M(out int)那么你可以说“int x = M(out x);”但你不能说“var x = M(out x);”因为要对M进行重载决策,我们需要知道x的类型,这是我们试图弄清楚的。说“var s; if(b)M(out s); s = 0;”是否合法?

我猜你问题的答案是相似的,例如,考虑到

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