Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/257.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 事件约定-I don';我不明白_C#_Events_Conventions - Fatal编程技术网

C# 事件约定-I don';我不明白

C# 事件约定-I don';我不明白,c#,events,conventions,C#,Events,Conventions,我的班级有一个活动: public class WindowModel { public delegate void WindowChangedHandler(object source, WindowTypeEventArgs e); public event WindowChangedHandler WindowChanged; public void GotoWindow(WindowType windowType) { this.cu

我的班级有一个活动:

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));
    }
}
派生事件类:

public class WindowTypeEventArgs : EventArgs
{
    public readonly WindowType windowType;

    public WindowTypeEventArgs(WindowType windowType)
    {
        this.windowType = windowType;
    }
}
将其注册到事件的其他一些类:

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

private void ChangeWindow(object sender, WindowTypeEventArgs e)
{
   //change window
}
我从遵循.Net惯例中获得了什么? 签订这样的合同更有意义

public delegate void WindowChangedHandler(WindowType windowType);
public event WindowChangedHandler WindowChanged;
这样做,我不需要创建新类,而且更容易理解。
我不是在为.Net库编写代码。此代码仅用于此项目中。我喜欢约定,但在本例中,我说的没有意义,或者我误解了什么,这是对的吗?

您可以使用您的委托。没有人会强迫你。这只是一个很好的活动模式


如果您使用standart Sender EventArgs模式,您也可以对其他事件使用相同的ChangeWindow处理程序。

我意识到您的困惑!当我第一次看到这个的时候,我也有同样的感觉

要认识到的一件大事是,从编程角度讲,它并没有给您带来太多的优势,但它是框架中众所周知的约定。因此,很多工具都希望使用
void EventName(objectsender,EventArgs e)
签名。例如,某些IoC容器可以使用此签名在构造时自动连接事件


简言之,这看起来有点奇怪,但这是一个惯例。坚持下去,灯泡最终会亮起来的

孤立地看,是的,你是对的:.NET传统语法更详细,更不直观,但有以下优点:

  • 对事件传递的信息的未来更改不会自动要求对事件的每个使用者进行更改。例如,如果您想向事件中添加一条附加信息(例如,
    WindowTitle
    字符串),则必须修改附加到该事件的每个函数的签名,而不管它们是否使用该签名。使用
    EventArgs
    方法,可以将属性添加到参数中,并且只更改需要利用附加信息的函数
  • 由于.NET 2.0引入了
    EventHandler
    委托类型,您不再需要手动定义自己的事件委托。在您的示例中,您可以将事件键入为
    EventHandler
    ,而不是
    WindowChangedHandler
  • EventArgs
    方法可以轻松地将多种类型的信息传递回调用函数。如果您需要在另一个示例中执行此操作(直接传递事件参数),那么您仍然需要创建自己的-tuple类来保存信息
当您在创建实际执行调用的受
保护的虚拟
函数时查看.NET事件的实际模式时,第一个事件的影响就更加明显了。例如:

public event EventHandler<WindowTypeEventArgs> WindowChanged;

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

    if(evt != null) evt(this, e);
}
公共事件事件处理程序窗口已更改;
WindowChanged上受保护的虚拟无效(WindowTypeEventArgs e)
{
var evt=窗口更改;
如果(evt!=null)evt(this,e);
}
这里有几件事我想指出:

  • 使用创建此事件调用方法的模式允许您在整个代码中避免空检查(没有附加任何函数的事件将为
    null
    ,如果您尝试调用它,将引发异常)
  • 此模式还允许从您继承的类控制调用顺序,允许它们在任何外部使用者之前或之后显式执行代码
  • 这在多线程环境中尤其重要。如果您刚才说
    If(WindowChanged!=null)WindowChanged(this,e)
    ,则在您检查它和调用它的时间之间,实际上会有
    WindowChanged
    事件变为
    null
    的风险。这在单线程场景中并不重要,但却是一个很好的防御习惯

  • 我真的很喜欢这个答案!第一点很明显,但我并没有想到。第二点我不知道,但很好:)我不确定我是否理解你的第三点。谢谢@很高兴这有帮助!我的第三点是关于能够将数据发送回调用事件的对象。使用
    EventArgs
    方法,您可以允许事件的使用者修改其上的属性,如
    CancelEventArgs
    类上的属性,这将允许它将数据传递回您。