一旦被触发,匿名代表是否可以取消订阅自己的活动?

时间:2010-06-21 04:36:54

标签: c# .net events delegates lambda

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

对于上下文,这是我的情况。用户已登录,并处于就绪状态以处理工作项。他们收到一个工作项目,处理它,然后再回去准备好。在这一点上,他们可能想说他们没有更多的工作项目,但无论如何都要发送给他们。我希望能够做到的是,只要该操作成为可能,就允许用户“排队”“我不可用”。

public event SomeHandler StateChanged = delegate {};

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

就我的目的而言,如果一个单独的线程发生触发事件并且这个特定的处理程序运行两次,那么这不是问题。要求相同的功能非常接近是可以接受的。我只是不希望它每次都允许操作。

3 个答案:

答案 0 :(得分:40)

您可以在订阅活动之前保存代理的实例:

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

我相信应该这样做......我必须将初始handler = null放在那里,否则你会得到'使用未分配的局部变量'编译错误,但我认为它实际上是良性的。

答案 1 :(得分:2)

从C#7.0开始,C#支持local functions

  

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

public void QueueNotAvailable() 
{
    void handler(object sender, EventArgs e)
    {
        // do something
        StateChanged -= handler;
    }
    StateChanged += handler;
}

答案 2 :(得分:0)

迪恩·哈丁(Dean Harding)提出的方法就像一个咒语,但是您需要为每个事件添加2行,并且每个处理程序都需要一个名称,这会使代码更加混乱。为了避免这种情况,您可以编写一些类似于以下内容的智能委托:

public delegate void SmartAction<T>(SmartAction<T> self, T data);

public event SmartAction<int> ProgressChanged;

ProgressChanged += (self, progress) => 
{ 
  Console.WriteLine(progress);
  ProgressChanged -= self;
};