可遇不可求的Question之C#中的匿名事件导致内存泄露的解决篇

题设:

在C#中,匿名函数是一个很好用的语法,大大简化了语法编写复杂度,然而,在实际应用中,如果频繁使用了匿名函数,匿名事件,会导致严重的资源泄露,甚至于内存崩溃.但是,由于匿名函数本身不存在引用的对象.因此,导致将其取消订阅或取消引用非常困难.

分析:

如果使用匿名函数订阅事件,事件的取消订阅过程将比较麻烦。 这种情况下若要取消订阅,必须返回到该事件的订阅代码,将该匿名方法存储在委托变量中,然后将此委托添加到该事件中。 一般来说,如果必须在后面的代码中取消订阅某个事件,则建议您不要使用匿名函数订阅此事件。

要防止在引发事件时调用事件处理程序,请取消订阅该事件。 要防止资源泄露,应在释放订户对象之前取消订阅事件。 在取消订阅事件之前,在发布对象中作为该事件的基础的多路广播委托会引用封装了订户的事件处理程序的委托。 只要发布对象保持该引用,垃圾回收功能就不会删除订户对象。

解决:

这里介绍一种,简单的技巧来解决匿名事件,匿名函数的无法取消订阅问题,大家直接看代码就能理解了^_^

EventHandler handler = null;

initializer.ResReady += handler = (s, e) => {

initializer.ResReady -= handler;

//do something ...

}

简而言之,就是必须给匿名事件实现准备好一个引用容器,引用对象,或者说是"引用地址",

EventHandler handler = null;

handler = (s, e) => {

并在声明匿名函数,匿名事件内部,自动将该引用容器释放掉.

initializer.ResReady -= handler;

参考:

C#中的事件尽量还是不要写成匿名形式,在需要销毁某个对象时一定要注销掉它曾经注册过的所有事件才能完全释放掉所占用的内存,否则极易造成内存泄露,

http://msdn.microsoft.com/zh-cn/library/ms366768.aspx

如何:订阅和取消订阅事件(C# 编程指南)

使用匿名方法订阅事件

  • publisher 才能订阅其事件。

    复制

      publisher.RaiseCustomEvent += delegate(object o, CustomEventArgs e)
        {
        string s = o.ToString() + " " + e.ToString();
        Console.WriteLine(s);
        };
        

    匿名函数(C# 编程指南)。