如何将自己从事件处理程序中删除? [英] How to remove yourself from an event handler?

查看:90
本文介绍了如何将自己从事件处理程序中删除?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要做的基本上是从事件中删除一个函数,而又不知道函数的名称。

What I want to do is basically remove a function from an event, without knowing the function's name.

我有一个 FileSystemWatcher 。如果创建/重命名文件,它将检查其名称。如果匹配,则将其移动到特定位置。但是,如果文件被锁定,它将生成一个附加到计时器的滴答事件的lambda,直到文件未被锁定。如果不是,它将移动文件,然后将其从事件处理程序中删除。我已经看到了许多方法来做到这一点,例如保留实例或创建命名方法。我不能在这里做任何一个。我有什么选择?

I have a FileSystemWatcher. If a file is created/renamed it checks its name. If it matches, it then moves it to a specific location. However, if the file is locked, it makes a lambda that attaches to a timer's tick event, waiting until the file is not locked. When it isn't, it moves the file and then removes itself from the event handler. I've seen lots of ways to do this, like keeping the instance, or making a named method. I can't do either of those here. What are my options?

推荐答案

没有简单的方法可以实现这一目标。

There is no simple method to achieve this.

我不明白为什么您不能保存委托。您无需将实例另存为某个字段。它可以是您的匿名事件处理程序捕获的局部变量:

I don't see why you can't save the delegate. You don't have to save the instance as some field. It can be a local variable that is captured by your anonymous event handler:

EventHandler<TypeOfEventArgs> handler = null;
handler = (s, e) =>
{
    // Do whatever you need to do here

    // Remove event:
    foo.Event -= handler;
}

foo.Event += handler;

我想不出一个无法使用它的情况。

I can't think of a single scenario where you can't use this.

但是,如果您遇到这种情况,那将非常棘手。

您需要找到已添加为事件处理程序的委托。因为您没有保存它,所以很难获得它。没有 this 来获取当前执行方法的委托。

However, if you have such a scenario, it get's quite tricky.
You need to find the delegate that has been added as a handler to the event. Because you didn't save it, it is pretty hard to obtain it. There is no this to get a delegate of the currently executing method.

您不能使用 GetInvocationList() ,因为在定义该类的类之外访问事件仅限于添加和删除处理程序,即 + = - =

也无法创建新的委托。尽管可以访问定义匿名方法的 MethodInfo 对象,但无法访问声明了该方法的类的实例。此类是自动生成的通过编译器并在匿名方法内调用 this ,将返回定义常规方法的类的实例。

Creating a new delegate isn't possible either. While you can get access to the MethodInfo object defining your anonymous method, you can't get access to the instance of the class that method is declared in. This class is generated automatically by the compiler and calling this inside the anonymous method will return the instance of the class your normal method is defined in.

我发现可行的唯一方法是找到事件使用的字段(如果有)并在其上调用 GetInvocationList()。下面的代码通过一个虚拟类对此进行了演示:

The only way I found that works is to find the field - if any - that the event uses and call GetInvocationList() on it. The following code demonstrates this with a dummy class:

void Main()
{
    var foo = new Foo();
    foo.Bar += (s, e) => {
        Console.WriteLine("Executed");

        var self = new StackFrame().GetMethod();
        var eventField = foo.GetType()
                            .GetField("Bar", BindingFlags.NonPublic | 
                                             BindingFlags.Instance);
        if(eventField == null)
            return;
        var eventValue = eventField.GetValue(foo) as EventHandler;
        if(eventValue == null)
            return;
        var eventHandler = eventValue.GetInvocationList()
                                     .OfType<EventHandler>()
                                     .FirstOrDefault(x => x.Method == self)
                               as EventHandler;
        if(eventHandler != null)
            foo.Bar -= eventHandler;
    };

    foo.RaiseBar();
    foo.RaiseBar();
}

public class Foo
{
    public event EventHandler Bar;
    public void RaiseBar()
    { 
        var handler = Bar;
        if(handler != null)
            handler(this, EventArgs.Empty);
    }
}

请注意,字符串传递给 GetField 的 Bar 必须是事件使用的 field 的确切名称。这导致两个问题:

Please note that the string "Bar" that is passed to GetField needs to be the exact name of the field that is used by the event. This results in two problems:


  1. 字段的名称可以不同,例如使用显式事件实现时。您需要手动找出字段名称。

  2. 可能根本没有任何字段。如果事件使用显式事件实现并且仅委托给另一个事件或以其他方式存储委托,则会发生这种情况。



结论:



另一种方法依赖于实现细节,因此,如果可以避免,请不要使用它。

Conclusion:

The alternative approach relies on implementation details, so don't use it if you can avoid it.

这篇关于如何将自己从事件处理程序中删除?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆