什么是在c#中取消订阅事件的正确方法?

我有一个模型类,其中包含我从其他类订阅的事件。 我想在每个类中正确订阅和取消订阅。

  • 首先,我想保证在MyClass中我只取消一次,即使代码只有少数方法。
  • 其次除了MyClass之外还有其他类使用OnMyEvent,因此我不想无意中取消订阅该类中的事件。

    MyClass(IModel model) { _model = model; _model.OnMyEvent +=EventHandle; } Close() { _model.OnMyEvent -=EventHandle; } Disconnect() { //I want to check if OnMyEvent has already unsibscribed //Moreover OnMyEvent is used in other classes and //I don't want to mess up with it here _model.OnMyEvent -=EventHandle; } 

如果您只订阅一次,那么取消订阅的次数并不重要 – 当您没有订阅时取消订阅是无操作。 同样,事件API的重点是您不能意外取消订阅其他订阅(其他类型或相同类型的其他实例)。

因此,显示的代码应该没问题,尽管将两个调用移动到处理此问题的单个方法可能是值得的。 但这可能有点矫枉过正了。

此外,如果您的类型是IDisposable ,请确保它也在该代码路径中被调用(可能通过调用Close() )。

您可以安全地多次取消订阅事件中的相同处理程序。 不需要额外的检查,这将是反作用的。

如果您想保证只取消订阅一次,可以使用GetInvocationList方法:

 if (_model.OnMyEvent != null && _model.GetInvocationList().Contains(EventHandle)) { _model.OnMyEvent -= EventHandle } 

但正如其他人所提到的,您可以多次取消订阅。 如果这确实不是问题,请保持这种状态。 我提出的解决方案只是代码噪声。 只需在一行中取消订阅就更简洁,当您的课程开始成长时更容易阅读。

您还可以使用此声明控制订阅和取消订阅。 但您还必须遍历字典并调用手动订阅的委托。

  private Dictionary TestEvents { get; } public event EventHandler TestEvent { add { string name = value.GetType().FullName; if (!TestEvents.ContainsKey(name)) { TestEvents.Add(name, value); } } remove { string name = value.GetType().FullName; if (TestEvents.ContainsKey(name)) { TestEvents.Remove(name); } } }