16

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

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

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.
4

2 回答 2

17

有趣的问题。

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

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

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

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

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

所以,我们没有令人信服的理由来做这个功能。具有 out/ref 参数的委托相对较少。将 lambda 分配给这些代表的情况更加罕见。所以这是一个我们不需要的功能,几乎没有人受益。

C# 3 是 Visual Studio 计划中的“长杆”;在 VS 中发布组件的所有团队中,我们安排的工作天数最多。这意味着我们每天都在拖延时间,整个部门都在拖延。这对花时间在对任何人都没有好处的不必要的功能上是一种强大的抑制。所以这项工作从未完成。

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

于 2010-01-02T20:49:24.677 回答
2

来自Eric Lippertvar关于为什么不能拆分变量的声明和赋值的评论:

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

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

D a = (out var x) => x = M(out x);
于 2010-01-02T04:31:58.297 回答