c# - 这个 object-lifetime-extending-closure 是 C# 编译器错误吗?

标签 c# memory-leaks lambda closures object-lifetime

我正在回答 question关于闭包(合法地)延长对象生命周期的可能性,当我遇到一些非常好奇的 C# 编译器代码生成(如果重要的话是 4.0)。

我能找到的最短的重现如下:

  1. 创建一个在调用包含类型的static 方法时捕获本地的 lambda。
  2. 将生成的委托(delegate)引用分配给包含对象的实例字段。

结果:编译器创建一个引用创建 lambda 的对象的闭包对象,但它没有理由这样做 - 委托(delegate)的“内部”目标是一个静态方法,并且执行委托(delegate)时,不需要(也不会)触及 lambda-creating-object 的实例成员。实际上,编译器就像程序员捕获了 this 一样。没有理由。

class Foo
{
    private Action _field;

    public void InstanceMethod()
    {
        var capturedVariable = Math.Pow(42, 1);

        _field = () => StaticMethod(capturedVariable);
    }

    private static void StaticMethod(double arg) { }
}

发布版本生成的代码(反编译为“更简单的”C#)如下所示:

public void InstanceMethod()
{

    <>c__DisplayClass1 CS$<>8__locals2 = new <>c__DisplayClass1();

    CS$<>8__locals2.<>4__this = this; // What's this doing here?

    CS$<>8__locals2.capturedVariable = Math.Pow(42.0, 1.0);
    this._field = new Action(CS$<>8__locals2.<InstanceMethod>b__0);
}

[CompilerGenerated]
private sealed class <>c__DisplayClass1
{
    // Fields
    public Foo <>4__this; // Never read, only written to.
    public double capturedVariable;

    // Methods
    public void <InstanceMethod>b__0()
    {
        Foo.StaticMethod(this.capturedVariable);
    }
}

观察 <>4__this闭包对象的字段填充了一个对象引用,但从未被读取(没有原因)。

那么这里发生了什么?语言规范允许吗?这是一个编译器错误/奇怪还是有一个很好的理由(我显然没有)让闭包引用该对象?这让我很焦虑,因为这看起来像是喜欢闭包的程序员(比如我)无意中将奇怪的内存泄漏(想象一下如果委托(delegate)被用作事件处理程序)引入程序的秘诀。

最佳答案

这确实看起来像一个错误。谢谢你让我注意到它。我会调查一下。可能已经找到并修复了。

关于c# - 这个 object-lifetime-extending-closure 是 C# 编译器错误吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8419079/

相关文章:

c# - ASP.NET 中 AjaxMin 5.14 和 Report Viewer 的问题

iPhone SDK : [MobileOfferViewController _shouldUseKeyWindowStack]

c++ - Lambda 内循环

python - lambda 函数闭包捕获什么?

c# - 表达式树是线程安全的吗?

c# - 解析大双值C#

c# - 在 C# 中格式化小数,至少保留 2 位小数

c# - CertificateStore 的 Certificates.Find() 实际上并没有找到证书

ScheduledExecutorService 的 Java 内存泄漏

c# - Emgu CV - 内存泄漏(内存消耗)