如果事件在 .NET 中作为委托实现,那么 .event IL 部分的意义何在?
我在 Stack Overflow 上看到了一些非常好的问题,涉及委托、事件以及这两个功能的 .NET 实现。 特别是一个问题,“C# 事件在幕后如何工作?”,给出了一个很好的答案,很好地解释了一些微妙的观点。
上述问题的答案表明了这一点:
当您声明类似字段的事件时 ...编译器生成方法 和一个私有字段(相同类型 作为代表)。 班级内, 当您引用 ElementAddedEvent 时 你指的是领域。 外部 班级,你指的是 字段
从同一问题链接的 MSDN 文章(“类似字段的事件") 补充道:
引发事件的概念是 完全相当于调用 活动代表代表 — 因此,没有特殊的语言 用于引发事件的构造。
为了进一步检查,我构建了一个测试项目,以便查看事件和委托编译为的 IL:
public class TestClass
{
public EventHandler handler;
public event EventHandler FooEvent;
public TestClass()
{ }
}
我期望委托字段 handler
和事件 FooEvent
编译为大致相同的 IL 代码,并使用一些附加方法来包装对编译器生成的 FooEvent
字段的访问。 但生成的 IL 并不完全符合我的预期:
.class public auto ansi beforefieldinit TestClass
extends [mscorlib]System.Object
{
.event [mscorlib]System.EventHandler FooEvent
{
.addon instance void TestClass::add_FooEvent(class [mscorlib]System.EventHandler)
.removeon instance void TestClass::remove_FooEvent(class [mscorlib]System.EventHandler)
}
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed
{
// Constructor IL hidden
}
.field private class [mscorlib]System.EventHandler FooEvent
.field public class [mscorlib]System.EventHandler handler
}
由于事件只不过是具有编译器生成的 add
和 remove
方法的委托,因此我没想到会看到事件被视为比伊利诺伊州更重要的东西。 但是添加和删除方法是在以 .event
开头的部分中定义的,而不是像普通方法那样以 .method
开头。
我的最终问题是:如果事件简单地实现为具有访问器方法的委托,那么拥有 .event
IL 部分有什么意义? 如果没有这个,它们不能通过使用 .method
部分在 IL 中实现吗? .event
等同于 .method
吗?
I've seen some very good questions on Stack Overflow concerning delegates, events, and the .NET implementation of these two features. One question in particular, "How do C# Events work behind the scenes?", produced a great answer that explains some subtle points very well.
The answer to the above question makes this point:
When you declare a field-like event
... the compiler generates the methods
and a private field (of the same type
as the delegate). Within the class,
when you refer to ElementAddedEvent
you're referring to the field. Outside
the class, you're referring to the
field
An MSDN article linked from the same question ("Field-like events") adds:
The notion of raising an event is
precisely equivalent to invoking the
delegate represented by the event —
thus, there are no special language
constructs for raising events.
Wanting to examine further, I built a test project in order to view the IL that an event and a delegate are compiled to:
public class TestClass
{
public EventHandler handler;
public event EventHandler FooEvent;
public TestClass()
{ }
}
I expected the delegate field handler
and the event FooEvent
to compile to roughly the same IL code, with some additional methods to wrap access to the compiler-generated FooEvent
field. But the IL generated wasn't quite what I expected:
.class public auto ansi beforefieldinit TestClass
extends [mscorlib]System.Object
{
.event [mscorlib]System.EventHandler FooEvent
{
.addon instance void TestClass::add_FooEvent(class [mscorlib]System.EventHandler)
.removeon instance void TestClass::remove_FooEvent(class [mscorlib]System.EventHandler)
}
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed
{
// Constructor IL hidden
}
.field private class [mscorlib]System.EventHandler FooEvent
.field public class [mscorlib]System.EventHandler handler
}
Since events are nothing more than delegates with compiler-generated add
and remove
methods, I didn't expect to see events treated as anything more than that in IL. But the add and remove methods are defined in a section that begins .event
, not .method
as normal methods are.
My ultimate questions are: if events are implemented simply as delegates with accessor methods, what is the point of having a .event
IL section? Couldn't they be implemented in IL without this by using .method
sections? Is .event
equivalent to .method
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我不确定这是否令人惊讶...与属性与字段相比(因为属性在与事件相同的函数之前:通过访问器封装):
另外 - 事件不提及有关字段的任何内容; 它们仅定义访问器(添加/删除)。 委托支持者是一个实现细节; 碰巧的是,类似字段的事件将一个字段声明为支持成员 - 与自动实现的属性将一个字段声明为支持成员的方式相同。 其他实现也是可能的(并且非常常见,尤其是在表单等中)。
其他常见实现:
稀疏事件(控件等)-EventHandlerList(或类似):(
以上几乎是 win-forms 事件的支柱)
Facade(尽管这让“发送者”有点困惑;一些中间代码是通常很有帮助):(
以上也可用于有效地重命名事件)
I'm not sure that is surprising... compare to the same for properties vs fields (since properties before the same function as events: encapsulation via accessors):
Also - events do not mention anything about fields; they only define the accessors (add/remove). The delegate backer is an implementation detail; it just so happens that field-like-events declare a field as a backing member - in the same way that auto-implemented-properties declare a field as a backing member. Other implementations are possible (and very common, especially in forms etc).
Other common implementations:
Sparse-events (Controls, etc) - EventHandlerList (or similar):
(the above is pretty-much the backbone of win-forms events)
Facade (although this confuses the "sender" a little; some intermediary code is often helpful):
(the above can also be used to effectively rename an event)
事件与代表不同。 事件封装了添加/删除事件的处理程序。 处理程序由委托表示。
您可以为每个事件编写 AddClickHandler/RemoveClickHandler 等,但这会相对痛苦,并且不会让像 VS 这样的工具轻松地将事件与其他事件分开。
这实际上就像属性一样 - 您可以编写 GetSize/SetSize 等(就像在 Java 中所做的那样),但通过分离属性,可以使用语法快捷方式和更好的工具支持。
Events aren't the same as delegates. Events encapsulate adding/removing a handler for an event. The handler is represented with a delegate.
You could just write AddClickHandler/RemoveClickHandler etc for every event - but it would be relatively painful, and wouldn't make it easy for tools like VS to separate out events from anything else.
This is just like properties really - you could write GetSize/SetSize etc (as you do in Java) but by separating out properties, there are syntactical shortcuts available and better tool support.
拥有一对添加、删除方法的事件的要点是封装。
大多数情况下,事件按原样使用,但有时您不希望将附加到事件的委托存储在字段中,或者您希望对添加或删除事件方法进行额外处理。
例如,实现内存高效事件的一种方法是将委托存储在字典中而不是私有字段中,因为字段总是被分配,而字典仅在添加项目时才会增加大小。 此模型与 Winforms 和 WPF 使用的模型类似,可以有效利用内存(winforms 和 WPF 使用键控字典来存储委托而不是列表)
The point of having events that are a pair of add, remove, methods is encapsulation.
Most of the time events are used as is, but other times you don't want to store the delegates attached to the event in a field, or you want to do extra processing on add or remove event methods.
For example one way to implement memory efficient events is to store the delegates in a dictionary rather than a private field, because fields are always allocated while a dictionary only grows in size when items are added. This model is similar with what Winforms and WPF uses make make efficient use of memory (winforms and WPF uses keyed dictionaries to store delegates not lists)