gpt4 book ai didi

c# - 如何从事件处理程序中删除自己?

转载 作者:太空狗 更新时间:2023-10-29 18:07:28 32 4
gpt4 key购买 nike

我想做的基本上是在不知道函数名称的情况下从事件中删除函数。

我有一个 FileSystemWatcher。如果创建/重命名文件,它会检查其名称。如果匹配,则将其移动到特定位置。但是,如果文件被锁定,它会生成一个附加到计时器滴答事件的 lambda,等待文件未被锁定。如果不是,它会移动文件,然后从事件处理程序中删除自己。我见过很多方法可以做到这一点,比如保留实例或创建命名方法。我不能在这里做任何一个。我有哪些选择?

最佳答案

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

首选方法:

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

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

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

foo.Event += handler;

我想不出有哪个场景不能使用它。

不保存委托(delegate)的替代方法:

但是,如果您遇到这样的情况,那就很棘手了。
您需要找到已作为事件处理程序添加的委托(delegate)。因为你没有保存它,所以很难得到它。没有 this获取当前正在执行的方法的委托(delegate)。

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

创建一个新的委托(delegate)也是不可能的。虽然您可以访问 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<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);
}
}

请注意字符串 "Bar"传递给 GetField需要是事件使用的字段 的确切名称。这会导致两个问题:

  1. 该字段可以以不同的方式命名,例如使用显式事件实现时。您需要手动找出字段名称。
  2. 可能根本就没有字段。如果事件使用显式事件实现并仅委托(delegate)给另一个事件或以其他方式存储委托(delegate),则会发生这种情况。

结论:

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

关于c# - 如何从事件处理程序中删除自己?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16734755/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com