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

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

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

MyEvent += MyMethod;

我可以像这样取消订阅:

MyEvent -= MyMethod;

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

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

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


当前回答

如果最好的方法是在订阅的eventHandler上保持引用,则可以使用Dictionary来实现。

在本例中,我必须使用匿名方法为一组DataGridViews包含mergeColumn参数。

使用启用参数设置为true的MergeColumn方法启用事件,而使用设置为false的MergeColumn方法禁用事件。

static Dictionary<DataGridView, PaintEventHandler> subscriptions = new Dictionary<DataGridView, PaintEventHandler>();

public static void MergeColumns(this DataGridView dg, bool enable, params ColumnGroup[] mergedColumns) {

    if(enable) {
        subscriptions[dg] = (s, e) => Dg_Paint(s, e, mergedColumns);
        dg.Paint += subscriptions[dg];
    }
    else {
        if(subscriptions.ContainsKey(dg)) {
            dg.Paint -= subscriptions[dg];
            subscriptions.Remove(dg);
        }
    }
}

其他回答

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

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

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的回答,我把它作为灵感。

有一种方法可以通过自己实现闭包而不是lambda表达式来解决这个问题。

假设将用作捕获变量的类如下所示。

public class A
{
    public void DoSomething()
    {
        ...
    }
}

public class B
{
    public void DoSomething()
    {
        ...
    }
}

public class C
{
    public void DoSomething()
    {
        ...
    }
}

这些类将被用作捕获变量,因此我们对它们进行实例化。

A a = new A();
B b = new B();
C c = new C();

实现闭包类,如下所示。

private class EventHandlerClosure
{
    public A a;
    public B b;
    public C c;

    public event EventHandler Finished;

    public void MyMethod(object, MyEventArgs args)
    {
        a.DoSomething();
        b.DoSomething();
        c.DoSomething();
        Console.WriteLine("I did it!");

        Finished?.Invoke(this, EventArgs.Empty);
    }
}

实例化闭包类,创建一个处理程序,然后订阅事件并订阅从闭包类的Finished事件中取消订阅的lambda表达式。

var closure = new EventHandlerClosure
{
    a = a,
    b = b,
    c = c
};
var handler = new MyEventHandler(closure.MyMethod);
MyEvent += handler;
closure.Finished += (s, e)
{
    MyEvent -= handler;
}

一个简单的解决办法:

只需将eventandle变量作为参数传递给自身。 事件,如果你的情况下,你不能访问原始创建的变量,因为多线程,你可以使用这个:

MyEventHandler foo = null;
foo = (s, ev, mehi) => MyMethod(s, ev, foo);
MyEvent += foo;

void MyMethod(object s, MyEventArgs ev, MyEventHandler myEventHandlerInstance)
{
    MyEvent -= myEventHandlerInstance;
    Console.WriteLine("I did it!");
}
Action myDelegate = delegate(){Console.WriteLine("I did it!");};

MyEvent += myDelegate;


// .... later

MyEvent -= myDelegate;

只要保持对委托的引用。

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