事件惯例 - 我不明白

Mad*_*sen 6 c# events conventions

我的班级有一个事件:

public class WindowModel
{
    public delegate void WindowChangedHandler(object source, WindowTypeEventArgs e);
    public event WindowChangedHandler WindowChanged;  

    public void GotoWindow(WindowType windowType)
    {
        this.currentWindow = windowType;
        this.WindowChanged.Invoke(this, new WindowTypeEventArgs(windowType));
    }
}
Run Code Online (Sandbox Code Playgroud)

派生事件类:

public class WindowTypeEventArgs : EventArgs
{
    public readonly WindowType windowType;

    public WindowTypeEventArgs(WindowType windowType)
    {
        this.windowType = windowType;
    }
}
Run Code Online (Sandbox Code Playgroud)

其他一些将它注册到事件的类:

private void SetupEvents()
{
   this.WindowModel.WindowChanged += this.ChangeWindow;
}

private void ChangeWindow(object sender, WindowTypeEventArgs e)
{
   //change window
}
Run Code Online (Sandbox Code Playgroud)

我从遵循.Net惯例中获得了什么?签订这样的合同会更有意义

public delegate void WindowChangedHandler(WindowType windowType);
public event WindowChangedHandler WindowChanged;
Run Code Online (Sandbox Code Playgroud)

这样做,我不需要创建一个新类,更容易理解.我不是在编写.Net库.此代码仅用于此项目.我喜欢惯例,但是当我说在这个例子中它没有意义或者我没有理解某些东西时,我是对的吗?

Ada*_*son 15

孤立地看,是的,你是对的:.NET常规语法更冗长,更不直观,但有一些优点:

  • 对事件传递的信息的未来更改不会自动要求更改事件的每个使用者.例如,如果您想在事件中添加一条额外的信息 - 比如一个WindowTitle字符串 - 您将不得不修改附加到该事件的每个函数的签名,无论它们是否使用它.使用此EventArgs方法,您可以将属性添加到参数中,并仅更改需要利用其他信息的函数.
  • 由于.NET 2.0引入了EventHandler<TEventArgs>委托类型,因此您不再需要手动定义自己的事件委托.在您的示例中,您可以键入事件EventHandler<WindowTypeEventArgs>而不是WindowChangedHandler.
  • EventArgs方法可以轻松地将多种类型的信息传递回调用函数.如果您需要在替代示例(直接传递event参数)中执行此操作,您仍然最终会创建自己的-tuple类来保存信息.

当您在创建实际执行调用的函数时查看.NET事件的实际模式时,第一个的影响会更明显protected virtual.例如:

public event EventHandler<WindowTypeEventArgs> WindowChanged;

protected virtual void OnWindowChanged(WindowTypeEventArgs e)
{
    var evt = WindowChanged;

    if(evt != null) evt(this, e);
}
Run Code Online (Sandbox Code Playgroud)

我想在此指出几件事:

  1. 使用创建此事件调用方法的模式允许您避免在整个代码中进行空值检查(没有附加任何函数的事件将会发生,null并且如果您尝试调用它将引发异常)
  2. 此模式还允许从您继承的类控制调用顺序,允许它们在任何外部使用者之前或之后显式执行其代码
  3. 这在多线程环境中尤为重要.如果您刚刚说过if(WindowChanged != null) WindowChanged(this, e);,您实际上会冒着WindowChanged事件发生的风险,即null在您检查事件和调用事件之间.这在单线程场景中并不重要,但是形成的防守习惯很大.