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

时间:2011-06-22 07:28:02

标签: c# events

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

  • 首先,我想保证在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;
    }
    

4 个答案:

答案 0 :(得分:11)

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

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

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

答案 1 :(得分:2)

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

答案 2 :(得分:1)

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

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

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

答案 3 :(得分:1)

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

    private Dictionary<string, EventHandler> 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);
            }
        }
    }