【问题标题】:Detaching a null event handler分离空事件处理程序
【发布时间】:2012-07-23 23:38:57
【问题描述】:

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

第一:

myObject.someEvent -= null;

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

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

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

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

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

【问题讨论】:

    标签: c# memory-leaks event-handling


    【解决方案1】:

    来自docs

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

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

    【讨论】:

    • 退订它们的问题实际上是它们的处理方式相同。正如@Justin 指出的那样,如果没有指向匿名方法的变量,则用于确定新匿名函数相等性的编译器行为是未定义的。这意味着删除将不知道处理程序包含的匿名方法与它试图删除的方法相同。
    【解决方案2】:

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


    在第二种情况下,这完全取决于编译器是否认为两个 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);
    

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

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

    【讨论】:

    • 这真的很有趣,我从来没有意识到你可以用这种方式定义实现。谢谢!
    • @Devin 通过“实现定义”,我的意思是由编译器的实现定义 - 您(作为应用程序作者)无法定义此实现,无论编译器选择做什么,您都会陷入困境。
    【解决方案3】:

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

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

    如果它不是空操作,我希望第一个抛出(我看不出它如何做任何有用的事情。)

    【讨论】:

      【解决方案4】:

      似乎连添加都没关系:

      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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-11-27
        • 2019-11-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-25
        相关资源
        最近更新 更多