代码之家  ›  专栏  ›  技术社区  ›  Josh Smeaton

匿名委托一旦被激发,是否可以取消对事件的订阅?

  •  17
  • Josh Smeaton  · 技术社区  · 14 年前

    我想知道“最佳实践”是什么,当请求事件处理程序在触发一次后取消订阅它自己时。

    从上下文来看,这是我的情况。用户已登录,并处于处理工作项的就绪状态。他们收到一个工作项,处理它,然后重新准备。此时,他们可能想说他们不可用于更多的工作项,但仍会向他们发送一个工作项。我希望能够做的是,允许用户在操作完成后立即“排队”a“我不可用”。

    public event SomeHandler StateChanged = delegate {};
    
    public void QueueNotAvailable() 
    {
        StateChanged += (s,e) => {
                                     if (e.CanGoNotAvailable) { 
                                         someObject.NotAvailable();
                                         StateChanged -= {thishandler};
                                     }
                                 }
    }
    

    就我而言,如果一个单独的线程恰好触发了事件,并且这个特定的处理程序运行了两次,那么这不是问题。请求非常接近的相同功能是可以接受的。我只是不希望每次手术都能成功。

    3 回复  |  直到 6 年前
        1
  •  40
  •   Dean Harding    14 年前

    可以在订阅事件之前保存委托的实例:

    public void QueueNotAvailable() 
    {
        SomeHandler handler = null;
        handler = (s,e) {
            // ...
            StateChanged -= handler;
        };
        StateChanged += handler;
    }
    

    我相信这应该做到…我必须把首字母 handler = null 在这里,您会得到“未分配局部变量的使用”编译错误,但我认为它实际上是良性的。

        2
  •  2
  •   Jam    6 年前

    从C_7.0开始,C_支持 local functions .

    局部函数是嵌套在另一个成员中的类型的私有方法。只能从其包含成员调用它们。

    public void QueueNotAvailable() 
    {
        void handler(object sender, EventArgs e)
        {
            // do something
            StateChanged -= handler;
        }
        StateChanged += handler;
    }
    
        3
  •  0
  •   Deepscorn    6 年前

    迪安·哈丁建议的方法工作起来很有魅力,但是每个事件需要添加2行,每个处理程序需要一个名称,这使得代码更加混乱。为了避免这种情况,您可以编写如下智能委托:

    public delegate void SmartAction<T>(SmartAction<T> self, T data);
    
    public event SmartAction<int> ProgressChanged;
    
    ProgressChanged += (self, progress) => 
    { 
      Console.WriteLine(progress);
      ProgressChanged -= self;
    };