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

Jos*_*ton 17 .net c# events lambda delegates

我想知道什么是"最佳实践",当要求事件处理程序在解雇一次后取消订阅自己的时候.

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

public event SomeHandler StateChanged = delegate {};

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

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

Dea*_*ing 40

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

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

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

  • @Graphain:是的,但我认为编译出错所带来的"未分配使用局部变量",在这种特殊情况下,因为它是物理上是不可能(AFAICT)来调用匿名委托无需首先将其分配给变量.因此,委托人体内的"处理程序"不可能被取消分配.无论如何,它只有一个额外的线,所以没什么大不了的:) (3认同)

小智 7

从 C# 7.0 开始,C# 支持本地函数

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

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

  • 这和当前最佳答案之间有一个非常小的语义差异:这将为取消订阅分配第二个委托对象/实例;当然,在大多数情况下,这不会被注意到 (5认同)