放弃.NET中的标准EventHandler模式会损失什么?.NET中的事件有一个标准模式——它们使用一个委托类型,该类型接受一个名为sender的普通对象,然后是第二个参数中的实际“有效负载”,它应该从EventArgs派生。从EventArgs派生第二个参数的基本原理似乎很清楚(请参阅.NETFrameworkStandardLibraryAnnotatedReference)。它旨在确保随着软件的发展,事件接收器和源之间的二进制兼容性。对于每个事件,即使它只有一个参数,我们也会派生一个自定义事件参数类,该类具有包含该参数的单个属性,这样我们就可以保留在未来版本中向有效负载添加更多属性,而不会破坏客户端的现有功能代码。.在组件独立开发的生态系统中非常重要。但是我发现零参数也是如此。这意味着如果我的第一个版本中有一个没有参数的事件,我会写成:publiceventEventHandlerClick;...然后我做错了。如果我将未来的委托类型更改为一个新类作为其有效负载:publicclassClickEventArgs:EventArgs{......我将破坏与客户端的二进制兼容性。客户端最终绑定到接受EventHandler的内部方法add_Click的特定重载,如果我更改委托类型,则它们找不到该重载,因此会出现MissingMethodException。好的,如果我使用方便的通用版本呢?公共事件处理程序点击;不,还是错了,因为EventHandler不是EventHandler。因此,要获得EventArgs的好处,您必须从中获取,而不是直接使用它。如果你不这样做,你也可以不使用它(在我看来)。然后是第一个参数sender。对我来说,这似乎是邪恶耦合的秘诀。事件触发本质上是一个函数调用。一般来说,一个函数不应该能够通过堆栈挖掘并找出调用者是谁,并相应地调整它的行为吗?我们应该强制界面看起来像这样吗?publicinterfaceIFoo{voidBar(objectcaller,intactualArg1,...);毕竟,Bar的实现者可能想知道调用者是谁,这样他们就可以查询其他信息!我希望你现在正在呕吐。为什么事件不同?因此,尽管我已经准备好为我声明的每个事件创建一个单独的EventArgs派生类,只是为了让我值得使用EventArgs,但我绝对宁愿删除对象发送者参数。VisualStudio的自动完成功能似乎并不关心您为事件使用的委托-您可以键入+=[hitspace,return],它会为您编写一个匹配任何委托的处理程序方法。那么偏离标准模式会损失什么价值呢?作为附加问题,C#/CLR4.0将如何改变这一点,也许是通过委托的逆转?我试图对此进行调查,但遇到了另一个问题。我最初将问题的这一方面包含在另一个问题中,但它引起了混乱。将其分成三个总问题似乎有点多......更新:事实证明,我很好奇逆变对整个问题的影响!如其他地方所述,新的编译器规则在类型系统中留下了一个漏洞,该漏洞会在运行时爆炸。通过以不同于Action的方式定义EventHandler,可以有效地插入此漏洞。所以对于事件,为了避免这种类型的漏洞,你不应该使用Action。这并不意味着您必须使用EventHandler;这只是意味着,如果您使用的是通用委托类型,请不要选择启用了逆变的委托类型。没什么,你没有什么可失去的。自从.NET3.5出来后我就一直在使用Action,它更自然也更容易编程。我什至不再处理生成的事件处理程序的EventHandler类型,只需编写您想要的方法签名并用lambda连接起来:btnCompleteOrder.OnClick+=(o,e)=>_presenter.CompleteOrder();我也不喜欢事件处理程序模式。在我看来,Sender对象实际上并没有那么有用。如果事件表明某个对象发生了某些事情(例如更改通知),那么在EventArgs中获取信息会更有帮助。我能看到Sender的唯一用途是取消订阅事件,但并不总是很清楚应该取消订阅哪些事件。顺便说一句,如果我有我的想法,一个事件就不会是一个AddHandler方法和一个RemoveHandler方法;它只是一个AddHandler方法,它将返回一个可用于取消订阅的MethodInvoker。我没有Sender参数,而是第一个参数是取消订阅所需的MethodInvoker的副本(如果对象发现自己接收取消订阅者丢失的事件)。标准的MulticastDelegate不适合调度事件(因为每个订阅者应该收到不同的取消订阅委托)但取消订阅事件不需要通过调用列表进行线性搜索。以上是C#学习教程:放弃.NET中的标准EventHandler模??式,我会失去什么?如果所有分享的内容对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
