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

时间:2010-11-11 18:04:02

标签: c# .net events

上一篇文章:

Event Signature in .NET — Using a Strong Typed 'Sender'?

In a C# event handler, why must the “sender” parameter be an object?


Microsoft的约定和指南强制.NET用户使用特殊模式在.NET中创建,引发和处理事件。

活动设计指南http://msdn.microsoft.com/en-us/library/ms229011.aspx说明


引用:

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

  • 返回类型为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;
}

虽然这些指导原则没有说明为什么遵循这些惯例如此重要,让开发人员像猴子一样不知道为什么以及他们在做什么。

恕我直言,微软的.NET事件签名约定对你的代码不利,因为它们会在编码,编码和编码上花费额外的零效率工作:

  1. 编码“(MyObject)发送者”强制转换(不说99%的情况根本不需要发件人)
  2. 编码派生“MyEventArgs”以获取要在事件处理程序内传递的数据。
  3. 编码解除引用(需要数据时调用“e.MyData”而不是“数据”)
  4. 这并不难做到这一点,但实际上讲的是当我们不遵守微软的惯例时我们会失去什么,除非人们把你当作异教徒,因为你的行为与微软的惯例verges on blasphemy对抗:)< / p>

    你同意吗?

4 个答案:

答案 0 :(得分:3)

关于拥有强类型的发件人,我经常想知道自己。

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

修改

Jim Mischel在评论中提出了一个很好的观点。通过使发件人成为object,我们可以启用相同的事件方法,以便可以重复使用它来处理各种事件。例如,假设网格需要在以下情况下自行更新:

  • 用户点击“刷新”按钮或
  • 系统检测到已从服务器加载新条目。

然后你可以说出这样的话:

serverBus.EntryReceived += RefreshNeededHandler;
refreshButton.Click += RefreshNeededHandler;

...
public void RefreshNeededHandler(object sender, EventArgs args) 
{
    ...
}

当然,在实践中,我几乎没有任何关于这种重用的调用,而在很多情况下,我倾向于使用的第一件事是将sender强制转换为我的对象类型知道它必须是。如果我想重用这样的处理程序,我认为将两个处理程序都调用相同的方便方法就足够了。对我来说,事件处理程序在概念上应该处理特定对象组上的特定类型的事件。所以我个人并不相信object sender方法是最好的惯例。

但是,我可以想象这会非常方便的情况,比如你想记录每个被触发的事件。

答案 1 :(得分:3)

您将遇到的问题:

  1. 当你添加另一个参数时,你 将不得不改变你的活动 处理程序签名

  2. 当程序员第一次看时     您的代码,您的事件处理程序将     看起来不像事件处理程序。

  3. 尤其是后者可能比写5行课更浪费你的时间。

答案 2 :(得分:2)

我在不遵循惯例时看到的最大问题是,您将混淆习惯于以运行时库的方式处理事件的开发人员。我不会说约会好或坏,但肯定不是邪恶。 .NET开发人员了解并了解如何使用符合Microsoft指南编写的事件。在此基础上创建自己的事件处理机制可能在运行时更有效,甚至可能导致您认为更清晰的代码。但它会有所不同,你最终会在你的程序中处理两个事件处理“标准”。

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

答案 3 :(得分:1)

我使用强类型事件(而不是对象,因为它节省了我必须进行投射),它真的不难理解,“哦,看起来他们使用的是不是对象的类型”

对于eventArgs,你应该使用它来防止对象根据@StriplingWarrior回答而改变。

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