取消订阅 C# 中的匿名方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/183367/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Unsubscribe anonymous method in C#
提问by Eric
Is it possible to unsubscribe an anonymous method from an event?
是否可以从事件中取消订阅匿名方法?
If I subscribe to an event like this:
如果我订阅这样的事件:
void MyMethod()
{
Console.WriteLine("I did it!");
}
MyEvent += MyMethod;
I can un-subscribe like this:
我可以像这样取消订阅:
MyEvent -= MyMethod;
But if I subscribe using an anonymous method:
但是如果我使用匿名方法订阅:
MyEvent += delegate(){Console.WriteLine("I did it!");};
is it possible to unsubscribe this anonymous method? If so, how?
是否可以取消订阅此匿名方法?如果是这样,如何?
采纳答案by Jacob Krall
Action myDelegate = delegate(){Console.WriteLine("I did it!");};
MyEvent += myDelegate;
// .... later
MyEvent -= myDelegate;
Just keep a reference to the delegate around.
只需保留对委托的引用即可。
回答by Jon Skeet
From memory, the specification explicitly doesn't guarantee the behaviour either way when it comes to equivalence of delegates created with anonymous methods.
从记忆中,当涉及到使用匿名方法创建的委托的等效性时,规范明确不保证任何方式的行为。
If you need to unsubscribe, you should either use a "normal" method or retain the delegate somewhere else so you can unsubscribe with exactly the same delegate you used to subscribe.
如果您需要取消订阅,您应该使用“正常”方法或将委托保留在其他地方,以便您可以使用与订阅时完全相同的委托来取消订阅。
回答by casademora
Kind of lame approach:
一种蹩脚的方法:
public class SomeClass
{
private readonly IList<Action> _eventList = new List<Action>();
...
public event Action OnDoSomething
{
add {
_eventList.Add(value);
}
remove {
_eventList.Remove(value);
}
}
}
- Override the event add/remove methods.
- Keep a list of those event handlers.
- When needed, clear them all and re-add the others.
- 覆盖事件添加/删除方法。
- 保留这些事件处理程序的列表。
- 需要时,将它们全部清除并重新添加其他。
This may not work or be the most efficient method, but should get the job done.
这可能不起作用或不是最有效的方法,但应该可以完成工作。
回答by J c
One technique is to declare a variable to hold the anonymous method which would then be available inside the anonymous method itself. This worked for me because the desired behavior was to unsubscribe after the event was handled.
一种技术是声明一个变量来保存匿名方法,然后该变量将在匿名方法本身内部可用。这对我有用,因为所需的行为是在处理事件后取消订阅。
Example:
例子:
MyEventHandler foo = null;
foo = delegate(object s, MyEventArgs ev)
{
Console.WriteLine("I did it!");
MyEvent -= foo;
};
MyEvent += foo;
回答by J c
In 3.0 can be shortened to:
在 3.0 中可以缩短为:
MyHandler myDelegate = ()=>Console.WriteLine("I did it!");
MyEvent += myDelegate;
...
MyEvent -= myDelegate;
回答by Benjol
If you want to be able to control unsubscription then you need to go the route indicated in your accepted answer. However, if you are just concerned about clearing up references when your subscribing class goes out of scope, then there is another (slightly convoluted) solution which involves using weak references. I've just posted a question and answeron this topic.
如果您希望能够控制取消订阅,那么您需要按照您接受的答案中指示的路线进行。但是,如果您只关心在订阅类超出范围时清除引用,那么还有另一种(稍微复杂的)解决方案涉及使用弱引用。我刚刚发布了有关此主题的问答。
回答by hemme
Instead of keeping a reference to any delegate you can instrument your class in order to give the event's invocation list back to the caller. Basically you can write something like this (assuming that MyEvent is declared inside MyClass):
您可以检测您的类,以便将事件的调用列表返回给调用者,而不是保留对任何委托的引用。基本上你可以写这样的东西(假设 MyEvent 在 MyClass 中声明):
public class MyClass
{
public event EventHandler MyEvent;
public IEnumerable<EventHandler> GetMyEventHandlers()
{
return from d in MyEvent.GetInvocationList()
select (EventHandler)d;
}
}
So you can access the whole invocation list from outside MyClass and unsubscribe any handler you want. For instance:
因此,您可以从 MyClass 外部访问整个调用列表并取消订阅您想要的任何处理程序。例如:
myClass.MyEvent -= myClass.GetMyEventHandlers().Last();
I've written a full post about this tecnique here.
我写了一个完整的帖子关于这个tecnique这里。
回答by user3217549
if you want refer to some object with this delegate, may be you can use Delegate.CreateDelegate(Type, Object target, MethodInfo methodInfo) .net consider the delegate equals by target and methodInfo
如果你想用这个委托引用某个对象,可能你可以使用 Delegate.CreateDelegate(Type, Object target, MethodInfo methodInfo) .net 考虑委托等于 target 和 methodInfo
回答by Manuel Marhold
One simple solution:
一个简单的解决方案:
just pass the eventhandle variable as parameter to itself. Event if you have the case that you cannot access the original created variable because of multithreading, you can use this:
只需将 eventhandle 变量作为参数传递给自身。如果您遇到由于多线程而无法访问原始创建变量的情况,则可以使用以下方法:
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!");
}
回答by Larry
If the best way is to keep a reference on the subscribed eventHandler, this can be achieved using a Dictionary.
如果最好的方法是保留对订阅的 eventHandler 的引用,则可以使用 Dictionary 来实现。
In this example, I have to use a anonymous method to include the mergeColumn parameter for a set of DataGridViews.
在此示例中,我必须使用匿名方法为一组 DataGridView 包含 mergeColumn 参数。
Using the MergeColumn method with the enable parameter set to true enables the event while using it with false disables it.
使用 MergeColumn 方法并将 enable 参数设置为 true 会启用该事件,而将其与 false 一起使用则会禁用它。
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);
}
}
}