一尘不染

如何确保事件仅订阅一次

c#

我想确保只在特定类中为实例上的事件订阅一次。

例如,我希望能够执行以下操作:

if (*not already subscribed*)
{
    member.Event += new MemeberClass.Delegate(handler);
}

我将如何实施这样的警卫?


阅读 434

收藏
2020-05-19

共1个答案

一尘不染

如果您要在可以访问源代码的类上谈论事件,则可以将防护措施放置在事件定义中。

private bool _eventHasSubscribers = false;
private EventHandler<MyDelegateType> _myEvent;

public event EventHandler<MyDelegateType> MyEvent
{
   add 
   {
      if (_myEvent == null)
      {
         _myEvent += value;
      }
   }
   remove
   {
      _myEvent -= value;
   }
}

这样可以确保只有一个订阅者可以在提供事件的类的该实例上订阅事件。

编辑, 请查看有关以上代码为何是一个坏主意而不是线程安全的注释。

如果您的问题是客户端的单个实例进行了多次订阅(并且您需要多个订阅者),则客户端代码将需要处理该问题。所以更换

尚未订阅

第一次订阅该事件时会设置的客户端类的布尔成员。

编辑(接受后): 根据@Glen T(问题的提交者)的评论,他所接受的解决方案的代码在客户端类中:

if (alreadySubscribedFlag)
{
    member.Event += new MemeberClass.Delegate(handler);
}

其中yetSubscribedFlag是客户端类中的成员变量,该成员变量跟踪对特定事件的首次订阅。人们在这里查看第一个代码段时,请注意@Rune的注释-
以一种非显而易见的方式更改订阅事件的行为不是一个好主意。

编辑31/7/2009: 请参阅@Sam
Saffron的评论。正如我已经说过的,Sam同意这里介绍的第一种方法不是修改事件订阅行为的明智方法。该类的使用者需要了解其内部实现,以了解其行为。不大好。
@Sam
Saffron还评论了线程安全性。我假设他指的是可能的竞争状况,其中(接近)两个订户同时尝试订阅,他们可能都最终订阅了。可以使用锁来改善这一点。如果您打算更改事件订阅的工作方式,则建议您阅读有关如何使订阅的添加/删除属性线程安全的信息

2020-05-19