【发布时间】:2011-05-08 15:29:56
【问题描述】:
以前的帖子:
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 并且是对象类型。这是 引发事件的对象。
第二个参数名为 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% 的情况根本不需要发送者)
- 为要在事件处理程序内部传递的数据编码派生的“MyEventArgs”。
- 编码取消引用(在需要数据时调用“e.MyData”,而不仅仅是“数据”)
做到这一点并不难,但实际上,如果不遵守微软的惯例,我们会失去什么,除了人们认为你是异端,因为你的行为违反了微软的惯例verges on blasphemy :)
你同意吗?
【问题讨论】:
-
作为旁注,这条线是纯粹的邪恶:
if (ClientConnected != null) ClientConnected(...);。你不应该,ever 调用这样的事件,因为它假定没有人会从另一个线程中删除事件处理程序。你冒着在这里扔 NRE 的风险。你应该改为:var h = ClientConnected; if (h != null) h(...);. -
不幸的是,您的事件线程安全解决方案无法正常工作。请检查“The Wrong Solution #2, from the Framework Design Guidelines and MSDN”codeproject.com/Articles/37474/Threadsafe-Events.aspx(我无意让这个事件线程安全,这只是为了举例)但无论如何谢谢。