C#闭包对垃圾收集器的奇怪影响

iro*_*nic 7 .net c# garbage-collection weak-references

直接代码

class Program
{
    private static WeakReference<EventHandler<EventArgs>> _noClosure;
    private static WeakReference<EventHandler<EventArgs>> _closure;

    static void Main(string[] args)
    {
        Init();
        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();
        EventHandler<EventArgs> target;
        Console.WriteLine(_closure.TryGetTarget(out target));
        Console.WriteLine(_noClosure.TryGetTarget(out target));
    }

    class C { public void Go() { } }

    private static void Init()
    {
        _noClosure = new WeakReference<EventHandler<EventArgs>>((sender, args) =>
        {
        });

        var s = new C();
        _closure = new WeakReference<EventHandler<EventArgs>>((sender, args) =>
        {
              s.Go();
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

我从这段代码得到的输出是

False
True
Run Code Online (Sandbox Code Playgroud)

这怎么可能呢?

PS我试图弄清楚它是如何WeakEventManager工作的.

Jon*_*eet 6

编译器将_noClosure委托缓存在静态字段中,并在每次调用时重用它Init.每次都可以重复使用完全相同的实例.

将其与每次调用_closure的新实例相关联,即无法缓存.C()Init()

缓存_noClosure意味着对委托有强引用(字段),因此无法进行垃圾回收.

如果您运行ildasm应用程序,则可以看到所有这些操作.

  • @ironic:它**发生的事实是一个实现细节.**可能*发生的事实在规范中.(它表示同样的代表可以重复使用.) (3认同)