确保事件永远不会有多个订阅者

时间:2016-10-08 16:09:30

标签: c# .net events .net-core

我想确保特定事件永远不会有多个订阅者。在我的特殊情况下,拥有多个订阅者是没有意义的,如果可能会出现一些偷偷摸摸的问题。

附注:特别是,我的处理程序(订阅者)必须是async,并且在提升事件时我必须await。原因是这是一个网络套接字包装类,我提出了TextReceived事件,我不想在用户(订阅者)处理完最后一次TextReceived事件之前从套接字读取更多数据(因为用户通常会给套接字写一些回复,而多个正在进行的回调会导致冲突)。也许这种情况可以通过另一种方式更好地解决(没有异步事件),并且我试图解决错误的问题。如果是这样,怎么样?

这是我提出的解决方案,但我想知道它是否是唯一的选择,或者是否可以进一步简化。

这是我的代码:

    private TextReceivedAsyncHandler _textReceivedAsync;

    public event TextReceivedAsyncHandler TextReceivedAsync
    {
        add
        {
            if (_textReceivedAsync != null)
                throw new MultipleSubscribersNotAllowedException(eventName: nameof(TextReceivedAsync));

            _textReceivedAsync = value;
        }
        remove
        {
            _textReceivedAsync = null;
        }
    }

这是限制多个订阅者的最佳方式,还是可以提出更优雅的解决方案?我想过使用公共委托属性而不是事件,但这并没有解决任何问题,因为委托无论如何都是多播的。

1 个答案:

答案 0 :(得分:3)

我仍然建议公开委托本身。是的,委托是多播的,它仍然可以引用多种方法。但是,事件的语义假定多个订阅者的可能性,并且限制这一点对于代码的用户来说非常混乱。但是,如果您公开委托,那么很明显只有一个“订户”。要防止使用+=语法,您可以这样做:

private Func<YourEventArgs, Task> _callback;
public Func<YourEventArgs, Task> Callback
{
   set { _callback = value; }
}

用户可能仍然使用多种方法传递委托:

Func<YourEventArgs, Task> delegateA = ...;
Func<YourEventArgs, Task> delegateB = ...;
Callback = delegateA + delegateB;

但您的TextReceivedAsync事件也是如此,我认为这是订阅者自己的问题。

如果确实希望阻止多播代理,还有一个选项是:

private Func<YourEventArgs, Task> _callback;
public Func<YourEventArgs, Task> Callback
{
    set
    {
        if (value != null && value.GetInvocationList().Length > 1) {
            throw new Exception("...");
        }
        _callback = value;                
     }
 }