我想在运行时更改附加到BackgroundWorker
的委托。下面的东西可以工作吗?
DoWorkEvenHandler dweh = new DoWorkEventHandler(method1);
backgroundworker.DoWork += dweh;
并在稍后的某个时刻通过重新分配引用dweh
来更改与DoWork
关联的委托:
dweh = new DoWorkEventHandler(method2);
不可以,你不能将委托"分配"给事件处理程序。通过将处理程序添加到内部用于表示事件的底层委托的调用列表中,可以将处理程序附加到事件。这是设计好的!
不,您不能通过更改先前用于附加事件处理程序的引用所指向的对象来更改处理程序;部分原因是委托是不可变的,部分原因是您只是将引用更改为指向其他东西,而不是真正更改事件处理程序,这是您试图完成的。
为了改变委托,你必须首先删除前一个委托:
backgroundworker.DoWork -= dweh;
然后通过将其添加为事件的处理程序来分配一个新的:
backgroundworker.DoWork += new DoWorkEventHandler(method2);
注意
在大多数情况下,您可以使用以下语法从事件中删除处理程序(委托):
backgroundworker.DoWork -= new DoWorkEventHandler(mehtod1);
或使用隐式或显式方法组转换:
backgroundworker.DoWork -= (DoWorkEventHandler)mehtod1; // explicit convertion
// - or -
backgroundworker.DoWork -= mehtod1; // implicit (more compact)
但是根据具体情况,您可能需要维护对前一个委托的引用,以便能够稍后删除它。例如,这将适用于匿名方法或lambda表达式。
您可以使用众所周知的"额外的间接级别"来解决这个问题。像这样编写一个类:
public sealed class RedirectableDoWorkEventHandler
{
public RedirectableDoWorkEventHandler(DoWorkEventHandler handler)
{
Contract.Requires(handler != null);
_handler = handler;
}
public DoWorkEventHandler Handler
{
get
{
return _handler;
}
set
{
Contract.Requires(value != null);
_handler = value;
}
}
public void DoWork(object sender, DoWorkEventArgs e)
{
_handler(sender, e);
}
private DoWorkEventHandler _handler;
}
然后你可以像这样使用它:
public void Setup()
{
BackgroundWorker worker = new BackgroundWorker();
// ...
var handler = new RedirectableDoWorkEventHandler(handler1);
worker.DoWork += handler.DoWork;
// And then some time later...
handler.Handler = handler2; // Now DoWork will call handler2.
}
private void handler1(object sender, DoWorkEventArgs e)
{
// Whatever
}
private void handler2(object sender, DoWorkEventArgs e)
{
// Whatever
}
但说真的,这有什么意义呢?您不妨只使用一个简单的处理程序,并使用if
从选项中进行选择。我想在某些情况下,它可以帮助封装事物……YMMV .