我想确保特定事件永远不会有多个订阅者。在我的特殊情况下,拥有多个订阅者是没有意义的,如果可能会出现一些偷偷摸摸的问题。
附注:特别是,我的处理程序(订阅者)必须是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;
}
}
这是限制多个订阅者的最佳方式,还是可以提出更优雅的解决方案?我想过使用公共委托属性而不是事件,但这并没有解决任何问题,因为委托无论如何都是多播的。
答案 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;
}
}