c# 通过反射从 BackgroundWorker.DoWork 中删除所有事件处理程序



这个链接对我有帮助 - 如何从控件中删除所有事件处理程序

是的,我成功从控件和窗体中删除所有事件处理程序。

但我在后台工作者中失败了。

这是我的代码。

void ReadingCompleted()
{
//find fields
List<FieldInfo> liField=typeof(BackgroundWorker).GetFields(BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Public).ToList();
foreach(FieldInfo field in liField)
{
txtbox_log.Text += field.Name + "rn";
}
//below output list 
//canCancelWorker
//workerReportsProgress
//cancellationPending
//isRunning
//asyncOperation
//threadStart
//operationCompleted
//progressReporter
//doWorkKey
//runWorkerCompletedKey
//progressChangedKey
//remove all eventhandler
object key = typeof(BackgroundWorker).GetField("doWorkKey", BindingFlags.NonPublic | BindingFlags.Static);
EventHandlerList events = (EventHandlerList)typeof(Component)
.GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance)
.GetValue(this, null);
events.RemoveHandler(key, events[key]);
waitForm.Close();
}

强烈建议不要编写这样的代码。设计良好的实现应该不需要任意删除订阅到任何类的任何事件的所有处理程序,包括DoWork或其他BackgroundWorker事件。唯一应该删除处理程序的代码是添加处理程序的相同代码,并且该代码知道它添加了哪个处理程序,因此可以直接删除它。

也就是说,假设您发布的代码是在继承BackgroundWorker类的类中找到的,那么它对您不起作用的唯一原因是您尝试使用从GetField("doWorkKey", ...)调用中返回的FieldInfo对象作为事件处理程序的实际键,实际上您应该调用该对象的GetValue()方法来获取实际的键值。

正确的代码如下所示:

FieldInfo keyField = typeof(BackgroundWorker)
.GetField("doWorkKey", BindingFlags.NonPublic | BindingFlags.Static);
object key = keyField.GetValue(bw);

如果您发布的代码不在继承BackgroundWorker类的类中(或者,即使它是,但它不是您尝试修改的BackgroundWorker对象(,那么您就有第二个问题。在此处调用GetValue()方法时,还需要提供正确的BackgroundWorker实例:

EventHandlerList events = (EventHandlerList)typeof(Component)
.GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance)
.GetValue(this, null);

也就是说,您需要将引用传递给您尝试修改的实际BackgroundWorker对象,而不是将this传递给GetValue()方法。

最新更新