当WeakReference引用委托时,GC不会收集?

Car*_*ven 6 c# delegates weak-references

在我看来,当我WeakReference在对象类的委托方法上使用该类时,对象类被GC收集,但是还有另一个副本驻留在WeakReference

我觉得用文字解释很难.我举个例子.我有以下对象类调用TestObject:

class TestObject
{
    public string message = "";

    private delegate string deleg();

    public TestObject(string msg)
    {
        message = msg;
    }

    public Delegate GetMethod()
    {
        deleg tmp = this.TestMethod;
        return tmp;
    }

    public string TestMethod()
    {
        return message;
    }

}
Run Code Online (Sandbox Code Playgroud)

现在,在我的主要应用程序,我试图参见方法TestMethodTestObject通过WeakReference.目的是TestObject在所有硬参考都消失时由GC收集.这是我的主应用程序的样子:

static void Main(string[] args)
    {
        var list = new List<WeakReference>();
        var obj = new TestObject("Hello 1");
        list.Add(new WeakReference(obj.GetMethod()));
        Console.WriteLine("Initial obj: " + ((Delegate)list[0].Target).DynamicInvoke());      //Works fine
        obj = null;     //Now, obj is set to null, the TestObject("Hello 1") can be collected by GC
        GC.Collect();   //Force GC
        Console.WriteLine("Is obj null: " + ((obj) == null ? "True" : "False"));
        Console.WriteLine("After GC collection: " + ((Delegate)list[0].Target).DynamicInvoke());
        Console.ReadKey();
    }
Run Code Online (Sandbox Code Playgroud)

这是我运行上面代码时的输出:

在此输入图像描述

这是奇怪的事情.在第一行,obj可以打印,"Hello 1"因为它刚刚初始化并obj持有对该的引用TestObject.全对了.接下来,obj设置为nullobj = nullGC被迫收集.因此,在输出的第二行,objtruenull.最后在最后一行,由于GC已经收集了obj,我希望它可以抛出一个NullReferenceException或只是在输出上打印.但是,它实际上打印的内容与输出的第一行相同!TestObject此时GC 不应该收集吗?!

这引出了一个问题,如果我将obj设置为null之后,GC TestObject是否先obj收集了该信息.

如果我已经将整个对象传递给了WeakReference,即new WeakReference(obj)代替了代理WeakReference,那么它就会完美地运行.

不幸的是,在我的代码中,我需要传递给WeakReference一个委托.我怎样才能WeakReference正常工作,以便GC只能通过引用委托来收集对象?

Av *_*zur 6

我认为问题出在你的测试中 - 而不是在框架中.似乎将局部变量设置为null并不能达到预期效果.如果我们完全跳过局部变量,我们在'after'行得到预期的NullReferenceException:

static void Main(string[] args)
{
    var list = new List<WeakReference>();
    //var obj = new TestObject("Hello 1");
    list.Add(new WeakReference(new TestObject("Hello 1").GetMethod()));
    Console.WriteLine("Initial obj: " + ((Delegate)list[0].Target).DynamicInvoke());      //Works fine
    //obj = null;     //Now, obj is set to null, the TestObject("Hello 1") can be collected by GC
    GC.Collect();   //Force GC
    //Console.WriteLine("Is obj null: " + ((obj) == null ? "True" : "False"));
    Console.WriteLine("After GC collection: " + ((Delegate)list[0].Target).DynamicInvoke());
    Console.ReadKey();
}
Run Code Online (Sandbox Code Playgroud)