C# NET中事件签名的代码友好版本

C# NET中事件签名的代码友好版本,c#,.net,events,C#,.net,Events,以前的职位: Microsoft的约定和指导原则强制.NET用户使用特殊模式在.NET中创建、引发和处理事件 活动设计指南指出: 引文: 事件处理程序签名遵守以下约定: 返回类型为Void 第一个参数名为sender 类型为Object。这是 引发事件的对象 第二个参数名为e和 属于EventArgs类型或派生类型 EventArgs类。这是 事件特定数据 该方法只需要两个步骤 参数 这些约定告诉开发人员,(以下)更短、更明显的代码是有害的: public delegate voi

以前的职位:


Microsoft的约定和指导原则强制.NET用户使用特殊模式在.NET中创建、引发和处理事件

活动设计指南指出:


引文:

事件处理程序签名遵守以下约定:

  • 返回类型为Void

  • 第一个参数名为sender 类型为Object。这是 引发事件的对象

  • 第二个参数名为e和 属于EventArgs类型或派生类型 EventArgs类。这是 事件特定数据

  • 该方法只需要两个步骤 参数


这些约定告诉开发人员,(以下)更短、更明显的代码是有害的:

public delegate void ConnectionEventHandler(Server sender, Connection connection);

public partial class Server
{
    protected virtual void OnClientConnected(Connection connection)
    {
        if (ClientConnected != null) ClientConnected(this, connection);
    }

    public event ConnectionEventHandler ClientConnected;
}
(以下)较长且不太明显的代码是好的:

public delegate void ConnectionEventHandler(object sender, ConnectionEventArgs e);

public class ConnectionEventArgs : EventArgs
{
    public Connection Connection { get; private set; }

    public ConnectionEventArgs(Connection connection)
    {
        this.Connection = connection;
    }
}

public partial class Server
{
    protected virtual void OnClientConnected(Connection connection)
    {
        if (ClientConnected != null) ClientConnected(this, new ConnectionEventArgs(connection));
    }

    public event ConnectionEventHandler ClientConnected;
}
虽然这些指南没有说明为什么遵循这些约定如此重要,但却让开发人员表现得像猴子一样,不知道为什么和他们在做什么

恕我直言,Microsoft针对.NET的事件签名约定对您的代码有害,因为它们会导致在编码、编码、编码上花费额外的零效率工作:

  • 编码“(MyObject)sender”强制转换(不包括99%完全不需要sender的情况)
  • 为要在事件处理程序中传递的数据编写派生的“MyEventArgs”
  • 对解引用进行编码(当需要数据时调用“e.MyData”,而不仅仅是“data”)
  • 要做到这一点并不难,但实际上,当我们不遵守微软的惯例时,我们失去了什么,除了人们认为你是异教徒,因为你与微软的惯例对抗:)


    你同意吗?

    关于有一个强类型的发送者,我自己经常想知道

    关于EventArgs,我仍然建议您使用一个中间的EventArgs类,因为您可能希望在将来添加当前无法预见的事件信息。如果您一直使用特定的EventArgs类,那么只需更改该类本身以及触发该类的代码即可。如果按照示例传递连接,则必须重构每个事件处理程序

    编辑

    吉姆·米谢尔的评论很有道理。通过使发送方成为
    对象
    ,我们可以潜在地重用相同的事件方法来处理各种事件。例如,假设网格需要更新自身,如果:

    • 用户单击“刷新”按钮,或
    • 系统检测到已从服务器加载新条目
    你可以这样说:

    serverBus.EntryReceived += RefreshNeededHandler;
    refreshButton.Click += RefreshNeededHandler;
    
    ...
    public void RefreshNeededHandler(object sender, EventArgs args) 
    {
        ...
    }
    
    当然,在实践中,我几乎从未收到过这种重用的呼吁,而在许多情况下,我倾向于做的第一件事是将
    sender
    转换为我知道它必须是的对象类型。如果我想重用这样的处理程序,我认为让两个处理程序都调用相同的便利方法就足够容易了。对我来说,事件处理程序在概念上应该处理特定对象组上的特定类型的事件。因此,我个人并不认为
    对象发送者
    方法是最好的约定


    但是,我可以想象这样做非常方便的情况,比如如果您想记录每一个触发的事件。

    您将遇到的问题:

  • 当您添加另一个参数时,您 将不得不更改您的活动 处理程序签名

  • 当程序员第一次看到 您的代码、事件处理程序将 看起来不像事件处理程序


  • 尤其是后者可能会比编写一个5行的类浪费更多的时间。

    我认为不遵循约定的最大问题是,您会让习惯于以运行库的方式处理事件的开发人员感到困惑。我不会说公约是好是坏,但它肯定不是邪恶的。NET开发人员知道并理解如何处理按照Microsoft指南编写的事件。在此基础上创建自己的事件处理机制在运行时可能更有效,甚至可能导致生成您认为更干净的代码。但这将是不同的,您将在程序中使用两个事件处理“标准”


    我的立场是,使用一个不太理想的标准(只要它没有被严重破坏)比使用两个相互竞争的标准要好。

    我使用了强类型事件(而不是对象,因为它省去了我的强制转换),这真的不难理解,“哦,看,他们使用的类型不是对象”

    对于eventArgs,您应该在对象按照@StriplingWarrior answer更改时使用它


    我不明白开发人员为什么会对此感到困惑?

    作为旁注,这一行完全是邪恶的:
    if(ClientConnected!=null)ClientConnected(…)。您永远不应该调用这样的事件,因为它假设没有人会从另一个线程中删除事件处理程序。你冒着在这里扔NRE的风险。您应该这样做:
    var h=ClientConnected;如果(h!=null)h(…)。不幸的是,您的事件线程安全解决方案无法工作。请检查“错误的解决方案2,来自框架设计指南和MSDN”(我无意使此事件成为线程安全的,只是为了示例),但无论如何还是要感谢。好好阅读Lu4,谢谢。#2是我的第一个想法:“没有其他人会想玩(啊哼--‘代码’)你”1。在事件处理程序内传递数据的方式、是参数还是MyEventTargets类字段之间没有区别。2.这篇文章的目的是改变人们对事件处理程序的看法,开发人员将看到这种新的方法,在开始的5秒钟内会遇到挫折,但是t