我想要做的基本上是从事件中删除一个函数,而不知道函数的名称.
我有一个FileSystemWatcher
.如果创建/重命名文件,则检查其名称.如果匹配,则将其移动到特定位置.但是,如果文件被锁定,它会使一个lambda附加到计时器的tick事件,等待文件未被锁定.如果不是,则移动文件,然后从事件处理程序中删除自身.我已经看到很多方法可以做到这一点,比如保留实例,或者创建一个命名方法.我不能在这里做任何一件事.我有什么选择?
没有简单的方法来实现这一目标.
首选方法:我不明白为什么你不能保存代表.您不必将实例保存为某个字段.它可以是由匿名事件处理程序捕获的局部变量:
EventHandlerhandler = null; handler = (s, e) => { // Do whatever you need to do here // Remove event: foo.Event -= handler; } foo.Event += handler;
我想不出你不能使用它的单一场景.
替代方法而不保存委托:但是,如果你有这样的场景,它会非常棘手.
您需要找到已添加为事件处理程序的委托.因为你没有保存它,所以很难获得它.没有this
获得当前正在执行的方法的委托.
您也不能GetInvocationList()
在事件上使用,因为访问它所定义的类之外的事件仅限于添加和删除处理程序,即+=
和-=
.
也不可能创建新的委托.虽然您可以访问MethodInfo
定义匿名方法的对象,但您无法访问声明方法的类的实例.此类由编译器自动生成,并且this
在匿名方法内调用将返回实例你的常规方法定义的类.
我找到的唯一方法是找到事件使用并调用GetInvocationList()
它的字段(如果有的话).以下代码使用虚拟类演示了这一点:
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() .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); } }
请注意,"Bar"
传递给的字符串必须是事件使用GetField
的字段的确切名称.这导致两个问题:
该字段可以以不同方式命名,例如,在使用显式事件实现时.您需要手动找到字段名称.
可能根本没有任何领域.如果事件使用显式事件实现并且只是委托给另一个事件或以其他方式存储代理,则会发生这种情况.
替代方法依赖于实现细节,因此如果可以避免,请不要使用它.