C# 如果编译器为lambda生成了一个方法而不是一个类,它怎么会泄漏呢?

C# 如果编译器为lambda生成了一个方法而不是一个类,它怎么会泄漏呢?,c#,.net,C#,.net,在26点39分的“降低C#:代码中到底发生了什么?-David Wengier”演讲中,演示者说如果以下代码: 已由编译器降低为方法: 这可能是内存使用的一个潜在问题,我引述如下: 因为编译器不知道lambda的主体是做什么的, 这可能会导致整个C类必须继续存在于内存中 永远。如果类是Windows.Form,那么它可能有很多 资源 然后他说,出于这个原因,编译器实际上生成了一个类 我不明白为什么会出现内存泄漏。 例如,C#7本地函数实际上变成了方法,那么为什么它不适用于非捕获lambda呢

在26点39分的“降低C#:代码中到底发生了什么?-David Wengier”演讲中,演示者说如果以下代码:

已由编译器降低为方法:

这可能是内存使用的一个潜在问题,我引述如下:

因为编译器不知道lambda的主体是做什么的, 这可能会导致整个C类必须继续存在于内存中 永远。如果类是Windows.Form,那么它可能有很多 资源

然后他说,出于这个原因,编译器实际上生成了一个类

我不明白为什么会出现内存泄漏。
例如,C#7本地函数实际上变成了方法,那么为什么它不适用于非捕获lambda呢?

如果编译器生成一个非静态方法并将其绑定到一个
操作
,那么无论它是否在lambda中使用,
this
指针都必须与其绑定。如果没有
this
指针,就不能调用非静态方法;这是编译器无法绕过的VM级别限制。因此,
这个
指针被捕获,因此只要
操作
处于活动状态,类实例就会保持活动状态,例如,如果它绑定到一个长寿命的事件处理程序,这可能需要很长时间

但在我看来,整个争论都是从错误的地方开始的。他说,“你会认为它在概念上被降低到[同一类中的一个方法]。”然后他继续解释为什么这是个坏主意。但我认为这是一个草人的论点。为什么编译器首先要在同一个类上生成一个非静态方法?没有理由这么做。这当然不是C#设计师在为lambdas设计降幅时所采用的思路

相反,论点应该是这样的:lambda可以捕获它使用的东西(它是一个闭包)。为了捕获它们,需要一个存放它们的地方。因此,编译器生成一个类,其中包含用于捕获内容的字段

如果类碰巧没有捕获任何内容,则没有字段,但仍然存在一个类。现在,如果lambda没有捕获任何内容,编译器可以在包含类中生成一个静态方法,如果lambda只捕获
this
,则可以生成一个非静态方法。但这有两个问题:

  • 这些方法可以通过反思发现
  • 它增加了编译器的复杂性(对于不同的捕获模式,降低lambda的方式完全不同),但没有任何好处(另一种降低lambda的方式没有真正的优势)

所以编译器根本不这么做。作为优化,它所做的唯一一件事是,如果lambda是无状态的(即不捕获任何内容),则每次都重用lambda类的相同实例。这只是现有代码中的一个小分支,因此复杂性要小得多。

您可能希望将您的问题发送给他,以便他能来回答@mjwills我考虑过,但我希望你同意,这是一个更大的观众群。此外,从可发现性的角度来看,这里的一个问题可能对许多其他人有用too@DonBox我认为mjwills的意思是,你应该把问题保留在这里,但也可以在推特上给David Wengier一个问题的链接,这样如果他感兴趣,他就可以来这里留下答案。这样,你就可以从其他问题的答案中得到他的观点。谢谢。关于第一个论点,“•这些方法可以通过反射发现。”其他生成的东西不也是这样吗?例如,编译器实际上为本地函数生成静态方法