如何取消注册"匿名"事件处理程序

P.K*_*P.K 37 .net c# events delegates anonymous-methods

说如果我听一个事件:

Subject.NewEvent += delegate(object sender, NewEventArgs e)
{
    //some code
}); 
Run Code Online (Sandbox Code Playgroud)

现在我如何取消注册此活动?或者只是让内存泄漏?

dtb*_*dtb 42

为匿名委托的实例命名:

EventHandler<NewEventArg> handler = delegate(object sender, NewEventArgs e)
{
    //some code
};

Subject.NewEvent += handler;
Subject.NewEvent -= handler;
Run Code Online (Sandbox Code Playgroud)

  • @Reed:匿名委托具有创建闭包的额外好处,您无法使用非匿名方法.如果OP希望能够包含无法传递到eventargs的范围内值,那么这是最好的方法. (11认同)
  • 为什么这比仅仅使它成为非匿名方法更好?这是非常不太明显的. (4认同)
  • @PK:我认为这是你能得到的最接近的.您无法取消注册您无法引用的内容. (2认同)

Ree*_*sey 24

如果您需要取消注册事件,我建议您避免使用事件处理程序的匿名委托.

这是一种情况,将此分配给本地方法更好 - 您可以干净地取消订阅事件.

  • 我不能不同意这一点.闭合使您可以更清洁,更简洁地通过状态.创建小类并在其上设置状态是粗糙和hacky,因此难以维护. (10认同)
  • 我不同意 - 如果你需要创建一个闭包,那么你将不得不使用匿名方法. (8认同)
  • @ free-dom:总有一些选项可以避免关闭(最坏的情况是,你可以做编译器为你做的事情).大多数情况下,您计划取消订阅活动的事件处理程序不是IMO,非常适合您想要关闭的事件.您应该使用易于跟踪的类级别状态信息,而不是让编译器为您创建闭包.在这种情况下,闭包往往导致奇怪的,难以跟踪的问题随着时间的推移,并不是可维护的. (3认同)

Ian*_*Ian 21

要在第一次调用时删除处理程序:

//SubjectType Subject = ..... already defined if using (2)

EventHandler handler = null;
handler = delegate(object sender, EventArgs e)
{
    // (1)
    (sender as SubjectType).NewEvent -= handler;
    // or
    // (2) Subject.NewEvent -= handler;

    // do stuff here
};

Subject.NewEvent += handler;
Run Code Online (Sandbox Code Playgroud)


EKa*_*kov 6

您可以创建从所有事件侦听器取消注册的方法.这不完全是你想要的,但有时它可能是有帮助的.例如(这确实有效=)):

    class Program {
    static void Main(string[] args) {
        A someClass = new A();
        someClass.SomeEvent += delegate(object sender, EventArgs e) {
            throw new NotImplementedException();
        };

        someClass.ClearEventHandlers();
        someClass.FireEvent();

        Console.WriteLine("No error.");
    }

    public class A {
        public event EventHandler SomeEvent;

        public void ClearEventHandlers() {
            Delegate[] delegates = SomeEvent.GetInvocationList();
            foreach (Delegate delegate in delegates) {
                SomeEvent -= (EventHandler) delegate;
            }
        }

        public void FireEvent() {
            if (SomeEvent != null) {
                SomeEvent(null, null);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 不知道为什么这会被拒绝 - 当然,最好不要首先使用持久的匿名方法,但是如果你处于需要清理它们的情况,那么这种方法效果很好. (2认同)