是否可以从事件中取消订阅匿名方法?

如果我订阅了这样的活动:

void MyMethod()
{
    Console.WriteLine("I did it!");
}

MyEvent += MyMethod;

我可以像这样取消订阅:

MyEvent -= MyMethod;

但如果我使用匿名方式订阅:

MyEvent += delegate(){Console.WriteLine("I did it!");};

是否可以取消订阅此匿名方法?如果有,怎么做?


当前回答

Action myDelegate = delegate(){Console.WriteLine("I did it!");};

MyEvent += myDelegate;


// .... later

MyEvent -= myDelegate;

只要保持对委托的引用。

其他回答

自从c# 7.0局部函数特性发布以来,J C建议的方法变得非常简洁。

void foo(object s, MyEventArgs ev)
{
    Console.WriteLine("I did it!");
    MyEvent -= foo;
};
MyEvent += foo;

老实说,这里没有一个匿名函数作为变量。但我想在你的例子中使用它的动机可以应用到局部函数中。

如果您希望能够控制取消订阅,那么您需要按照您接受的答案中指示的路线进行。但是,如果您只关心在订阅类超出作用域时清除引用,那么还有另一种解决方案(有点复杂),它涉及使用弱引用。我刚刚就这个话题发布了一个问答。

如果你想用这个委托引用一些对象,你可以使用委托。创建elegate(类型,对象目标,MethodInfo MethodInfo) .net考虑委托equals by target和methodInfo

下面是一个简单的解决方案,它从事件中删除所有分配的方法。还有匿名方法。

使用这段代码并调整名称。

if (MyEvent != null)
    foreach (Delegate del in MyEvent.GetInvocationList())
        MyEvent -= (EventHandler<MyEventHandlerType>)del;

示例使用

public class SomeClass
{
  public event EventHandler<NiceEventArgs> NiceEvent;

  public void RemoveHandlers()
  {
    if (NiceEvent != null)
      foreach (Delegate del in NiceEvent.GetInvocationList())
        NiceEvent -= (EventHandler<NiceEventArgs>)del;
  }
}

感谢hemme的回答,我把它作为灵感。

为了将事件的调用列表返回给调用者,您可以对类进行仪器操作,而不是保持对任何委托的引用。基本上你可以这样写(假设MyEvent是在MyClass中声明的):

public class MyClass 
{
  public event EventHandler MyEvent;

  public IEnumerable<EventHandler> GetMyEventHandlers()  
  {  
      return from d in MyEvent.GetInvocationList()  
             select (EventHandler)d;  
  }  
}

因此,您可以从MyClass外部访问整个调用列表,并取消订阅任何您想要的处理程序。例如:

myClass.MyEvent -= myClass.GetMyEventHandlers().Last();

关于这个技巧,我已经写了一篇完整的文章。