namespace Test
{
class Test
{
delegate void HandleMessage(string message);
public void handleMessage(string message){}
static void Main(string[] args)
{
HandleMessage listener1 = new Test().handleMessage;
WeakReference w1 = new WeakReference(listener1);
HandleMessage listener2 = (message) => { };
WeakReference w2 = new WeakReference(listener2);
Console.WriteLine("w1.Target:\t[" + w1.Target + "]");
Console.WriteLine("w2.Target:\t[" + w2.Target + "]");
listener1 = null;
listener2 = null;
GC.Collect();
Console.WriteLine("after GC");
Console.WriteLine("w1.Target:\t[" + w1.Target + "]");
Console.WriteLine("w2.Target:\t[" + w2.Target + "]");
Console.ReadLine();
}
}
}
为什么 GC 后 w2.Target 不为空?
w1.Target:[Test.Test+HandleMessage] w2.Target:[Test.Test+HandleMessage] GC后 w1.目标:[] w2.Target:[Test.Test+HandleMessage]
编辑
感谢所有的答案,Brian Rasmussen 和 Jon Skeet 你的答案是正确的。现在我彻底明白了这是怎么回事,所以我又写了一个例子来让一切更清楚。
以下示例表明:
如果 Test#create() 没有引用任何实例属性或方法,那么编译器将创建“private static HandleMessage CS$<>9__CachedAnonymousMethodDelegate1”,就像 Jon Skeet 所说的那样 - 当你使用相同的lambda 表达式多次。
如果 Test#create() 确实引用了实例属性或方法,如下例调用 this.ToString(); 那么编译器无法创建静态方法来替换实例方法的逻辑,所以在GC之后可以收集HandleMessage实例。
namespace Test
{
class Test
{
public delegate void HandleMessage(string message);
public void handleMessage(string message)
{
}
public HandleMessage create()
{
return (message) => {
//this.ToString();
};
}
static void Main(string[] args)
{
HandleMessage listener1 = new Test().handleMessage;
WeakReference w1 = new WeakReference(listener1);
HandleMessage listener2 = new Test().create();//(message) => { };
WeakReference w2 = new WeakReference(listener2);
Console.WriteLine("w1.Target:\t[" + w1.Target + "]");
Console.WriteLine("w2.Target:\t[" + w2.Target + "]");
listener1 = null;
listener2 = null;
GC.Collect();
Console.WriteLine("after GC");
Console.WriteLine("w1.Target:\t[" + w1.Target + "]");
Console.WriteLine("w2.Target:\t[" + w2.Target + "]");
Console.ReadLine();
}
}
}