在C#中取消订阅匿名方法

Eri*_*ric 214 c# delegates anonymous-methods

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

如果我订阅这样的事件:

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

MyEvent += MyMethod;
Run Code Online (Sandbox Code Playgroud)

我可以这样取消订阅:

MyEvent -= MyMethod;
Run Code Online (Sandbox Code Playgroud)

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

MyEvent += delegate(){Console.WriteLine("I did it!");};
Run Code Online (Sandbox Code Playgroud)

是否有可能取消订阅这种匿名方法?如果是这样,怎么样?

Jac*_*all 221

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

MyEvent += myDelegate;


// .... later

MyEvent -= myDelegate;
Run Code Online (Sandbox Code Playgroud)

只需保持对代表的引用.


J c*_*J c 139

一种技术是声明一个变量来保存匿名方法,该方法随后可以在匿名方法本身中使用.这对我有用,因为在处理事件后所需的行为是取消订阅.

例:

MyEventHandler foo = null;
foo = delegate(object s, MyEventArgs ev)
    {
        Console.WriteLine("I did it!");
        MyEvent -= foo;
    };
MyEvent += foo;
Run Code Online (Sandbox Code Playgroud)

  • 我找到了我的dubt的答案,并且'foo'将真正地引用匿名方法itslef.捕获的变量被修改,因为它是在匿名方法分配给它之前捕获的. (7认同)
  • 这正是我所需要的!我错过了= null.(MyEventHandler foo = delegate {... MyEvent- = foo;}; MyEvent + = foo;无效...) (2认同)

Jon*_*eet 21

从内存中,当涉及使用匿名方法创建的委托的等效性时,规范明确地不保证行为.

如果您需要取消订阅,您应该使用"普通"方法或将代理保留在其他位置,以便您可以取消订阅您用于订阅的完全相同的委托.


小智 16

在3.0中可以缩短为:

MyHandler myDelegate = ()=>Console.WriteLine("I did it!");
MyEvent += myDelegate;
...
MyEvent -= myDelegate;
Run Code Online (Sandbox Code Playgroud)


maz*_*nko 10

由于C#7.0的本地功能功能已经发布,该办法建议通过Ĵç变得很整洁。

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

因此,说实话,您这里没有匿名函数作为变量。但是我想在您的情况下使用它的动机可以应用于局部函数。

  • 为了使可读性更好,您可以移动 MyEvent += foo; 行位于 foo 声明之前。 (2认同)

hem*_*mme 9

您可以检测您的类,而不是保留对任何委托的引用,以便将事件的调用列表返回给调用者.基本上你可以写这样的东西(假设MyEvent在MyClass中声明):

public class MyClass 
{
  public event EventHandler MyEvent;

  public IEnumerable<EventHandler> GetMyEventHandlers()  
  {  
      return from d in MyEvent.GetInvocationList()  
             select (EventHandler)d;  
  }  
}
Run Code Online (Sandbox Code Playgroud)

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

myClass.MyEvent -= myClass.GetMyEventHandlers().Last();
Run Code Online (Sandbox Code Playgroud)

我写了一个完整的帖子关于这个tecnique 这里.

  • 这是否意味着如果他们在我之后订阅,我可能会意外取消订阅不同的实例(即不是我)? (2认同)

cas*_*ora 6

一种蹩脚的方法:

public class SomeClass
{
  private readonly IList<Action> _eventList = new List<Action>();

  ...

  public event Action OnDoSomething
  {
    add {
      _eventList.Add(value);
    }
    remove {
      _eventList.Remove(value);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)
  1. 覆盖事件添加/删除方法.
  2. 保留这些事件处理程序的列表.
  3. 需要时,清除所有内容并重新添加其他内容.

这可能不起作用或者是最有效的方法,但应该完成工作.

  • 如果您认为它很蹩脚,请不要发布. (14认同)