【问题标题】:Reassign event handler at runtime在运行时重新分配事件处理程序
【发布时间】:2013-03-04 20:31:05
【问题描述】:

我想在运行时更改附加到BackgroundWorker 的委托。像下面这样的东西有用吗?

DoWorkEvenHandler dweh = new DoWorkEventHandler(method1);
backgroundworker.DoWork += dweh;

稍后通过重新分配引用 dweh 来更改与 DoWork 关联的委托:

dweh = new DoWorkEventHandler(method2);

【问题讨论】:

    标签: c# delegates event-handling


    【解决方案1】:

    不,您不能将委托“分配”给事件处理程序。处理程序通过将它们添加到内部用于表示事件的底层委托的调用列表来附加到事件。这是设计使然!

    不,您不能通过更改以前用于附加事件处理程序的引用所指向的对象来更改处理程序;部分原因是委托是不可变的,部分原因是您只是将引用更改为指向其他内容,而不是真正更改您要完成的事件处理程序。

    更改委托,您必须先删除之前的委托:

    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 表达式。

    【讨论】:

      【解决方案2】:

      您可以使用众所周知的“额外间接层级”来解决这个问题。像这样写一个类:

      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。

      【讨论】:

      • 当然,同样,您可以通过处理事件的方法中的一个分支来解决这个问题..
      • 正如您发表评论一样,我添加了一条额外的评论以达到同样的效果。所以我绝对同意你的看法。 :)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多