3

我被委托清理代码中的内存泄漏,并进行检查以防止进一步的泄漏。我注意到未分离的处理程序似乎是主要原因。大多数都是直截了当的,但是代码中有几件事让我摸不着头脑。

第一的:

myObject.someEvent -= null;

我假设这完全没有任何作用是正确的吗?(我知道如果一个事件是本地的,你可以将它设置为 null,因为它本质上是一个多播委托)。

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

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

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

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

4

4 回答 4

3

文档

请务必注意,如果您使用匿名函数订阅某个事件,您将无法轻松取消订阅该事件。要在这种情况下取​​消订阅,需要返回订阅事件的代码,将匿名方法存储在委托变量中,然后将委托添加到事件中。通常,如果您必须在稍后的代码中取消订阅事件,我们建议您不要使用匿名函数来订阅事件。

所以你是对的,你不能像那样删除匿名方法。同理,说 myObject.someEvent -= null;也无济于事

于 2012-07-23T15:26:48.993 回答
2

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


在第二种情况下,这完全取决于编译器是否认为两个 lambda 表达式相等。这篇博客文章间接回答了这个确切的问题

在 C# 中,如果你有:

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

<< snip >> 在 C# 中,这是由实现定义的;编译器可以自行决定是否使它们引用相等。

您可以确定当前的 C# 编译器是否相当容易地认为这两者相等,但这并不是重点——这是实现定义的行为,不应依赖。

于 2012-07-23T15:27:36.997 回答
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
于 2012-07-23T15:24:39.257 回答
0

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

正确的。每个 lambda 创建一个新的委托对象,它不等于第一个。

如果不是,我希望第一个抛出;ta no-op(我看不出它怎么能做任何有用的事情。)

于 2012-07-23T15:24:43.687 回答