事件监听器是否仅限于只有一个用户?

是否可以阻止多个订阅者订阅活动?

我已经创建了一个快速示例代码片段来给我的问题一些上下文,但不幸的是我现在无法测试它,因为我不在我的VS机器上。

目标是:

  • 如果没有订阅者,则返回空列表。
  • 返回单个订户的返回值。
  • 如果多个订户尝试订阅该事件,则抛出exception( 这是问题的关键 )。

这可能吗?

public delegate List GetWindowListDelegate(); public static event GetWindowListDelegate GetWindowListEvent; public List GetWindowList() { if (GetWindowListEvent == null) { return new List(); } return GetWindowListEvent(); } 

注意:我使用的是.NET 3.5 sp1。

听起来您不需要事件 – 只需公开委托本身并允许调用者自己设置委托引用。

您可以使用事件访问器来完成此任务。 类似于以下内容:

  private EventHandler _h; public event EventHandler H { add { if (...) { // Your conditions here. // Warning (as per comments): clients may not // expect problems to occur when adding listeners! _h += value; } } remove { _h -= value; } } 

正如安德鲁指出的那样,你真的不需要事件来完成这个任务。 你需要它们有什么特别的原因吗?

只是为了完成John的答案,这里是一个只允许一个处理程序的事件的工作实现:

 class Foo { private EventHandler _bar; public event EventHandler Bar { add { if (_bar != null || value.GetInvocationList().Length > 1) { throw new InvalidOperationException("Only one handler allowed"); } _bar = (EventHandler)Delegate.Combine(_bar, value); } remove { _bar = (EventHandler)Delegate.Remove(_bar, value); } } } 

请注意,公开委托而不是事件不会阻止多个处理程序:由于.NET委托是多播的,因此一个委托可以表示对多个方法的调用。 但是,您可以将委托作为属性公开,并在setter中执行与上面代码中相同的检查。

无论如何,正如其他人所指出的那样,防止一个事件的多个处理程序可能不是一个好主意……对于使用它的开发人员来说,这将是非常混乱的。

使用此代码,您将公开YourNameHere委托,但它将禁用+ =function,允许ONLY =。

 private Action yourNameHere; public Action YourNameHere { set { yourNameHere= value; } } 

希望能帮助到你。

当然可以实现您想要做的事情,但它不符合惯例 – 我会敦促您提出一个不涉及事件的不同解决方案。

正如Jon Skeet所解释的 ,公共事件是围绕多播委托的类似属性的包装器。

您可以将事件的标准实现视为事件发生时要调用的函数列表。

 // From the above link: // the exposed event public event EventHandler MyEvent // multicast delegate field private EventHandler _myEvent; // property-like add & remove handlers public event EventHandler MyEvent { add { lock (this) { _myEvent += value; } } remove { lock (this) { _myEvent -= value; } } } 

…当开发人员看到这样的事件时,他们希望能够毫无问题地订阅它,因为事件基本上说“任何类型的类型都可以注册以接收此事件通知”。

您似乎想要允许某人设置获取窗口列表的实现。 我建议做的是允许人们手动传入委托,然后持有一个委托实例。 明确表示只有一种方法可以设置它; 如果可能的话我会建议使用构造函数注入,因为这会消除所有歧义 – 你只能在构造时设置一次委托实例,然后它不再可以被公共API修改(所以B类不能破坏已经设置的委托)按A)类。

例如

 public class CallsDelegateToDoSomething { private Func> m_windowLister; public CallsDelegateToDoSomething(Func> windowFunc) { m_windowLister = windowFunc; } public List GetWindowList() { if (windowLister == null) { return new List(); } return m_windowLister(); } } 

如果您的设计不允许这样做,那么只需创建SetWindowLister(Func> windowLister)ClearWindowLister()方法。