分离空事件处理程序

时间:2012-07-23 15:16:28

标签: c# memory-leaks event-handling

我受委托清除代码中的内存泄漏,并进行检查以防止进一步泄漏。我注意到未分离的处理程序似乎是主要原因。大多数都是直截了当的,但代码中有一些东西让我抓狂。

首先:

myObject.someEvent -= null;

我是否正确假设绝对没有? (我知道如果一个事件是本地的,你可以将它设置为null,因为它本质上是一个多播委托)。

其次,对于匿名处理程序:

myObject.someEvent += ()=> { x + y; };
myObject.someEvent -= ()=> { x + y; };

我是否正确地说第二条指令也毫无价值,因为匿名方法将被编译为两个单独的委托,因此减法实际上并不指向需要删除的正确处理程序? (对于任何寻找合适解决方案的人来说,请查看here)。

我不想满足于“是的,那是对的”,我想知道为什么这些东西不起作用(假设我的断言是正确的)。

4 个答案:

答案 0 :(得分:3)

来自docs

  

重要的是要注意,如果您使用匿名函数订阅它,则无法轻松取消订阅事件。要在此方案中取消订阅,必须返回订阅事件的代码,将匿名方法存储在委托变量中,然后将委托添加到事件中。一般情况下,如果您必须在代码中稍后取消订阅该事件,我们建议您不要使用匿名函数订阅事件。

所以你是对的,你不能删除那样的匿名方法。以类似的方式,说myObject.someEvent -= null;也将无所作为

答案 1 :(得分:2)

在第一种情况下,我们可以从MulticastDelegate.CombineImpl的反编译实现中看到(使用IL Spy或其他东西),如果传入的委托是null,那么就不会进行组合 - 所以是的,删除一个null delegate什么都不做。


在第二种情况下,它取决于编译器是否认为两个lambda表达式相等。这个确切的问题在this blog article

中间接回答
  如果你有以下内容,请在C#中

Func<int, int> f1 = (int x)=>x + 1;
Func<int, int> f2 = (int x)=>x + 1;
bool b = object.ReferenceEquals(f1, f2);
     

&LT;&LT; snip&gt;&gt; 在C#中,这是实现定义的;编译器   可以选择让他们自行决定是否参考。

你可以弄清楚当前的C#编译器是否认为这两者是相等或不相当容易的,但这不是真正的重点 - 这是实现定义的行为,不应该依赖它。

答案 2 :(得分:0)

似乎即使添加也无关紧要:

public Action  del;
void Main()
{

del+=(()=>"1".Dump());

 del+=null;
 del+=null;
 del+=null; 

del+=(()=>"2".Dump());
del();
del.GetInvocationList().Select(f=>f.Target);

}



//ouput:
1
2

答案 3 :(得分:0)

  

第二条指令也毫无价值,因为匿名方法将被编译为两个单独的委托,因此减法实际上并没有指向需要删除的正确处理程序?

正确。每个lambda创建一个新的委托对象,它不会与第一个对象相同。

我希望第一个投掷,如果它不是;没有操作(我无法看到它如何做任何有用的事情。)