#c# #.net #events #.net-core
#c# #.net #Мероприятия #.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. Я не уверен, что в вашем подходе что-то не так; если вы хотите иметь больше контроля над ним, вы можете самостоятельно реализовать шаблон observer (любой, сделайте его асинхронным) или вместо этого создать свойство обратного вызова (менее НАДЕЖНОЕ).
Ответ №1:
Я бы все же предложил предоставить самому делегату. Да, делегаты являются многоадресными, и они все равно могут ссылаться на несколько методов. Однако семантика события предполагает возможность нескольких подписчиков, и ограничение этого очень сбивает с толку пользователей вашего кода. Однако, если вы предоставляете делегат, совершенно ясно, что ожидается только один «подписчик». Чтобы предотвратить использование =
синтаксиса, вы можете сделать это следующим образом:
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 amp;amp; value.GetInvocationList().Length > 1) {
throw new Exception("...");
}
_callback = value;
}
}