如果事件在.NET中作为代理实现,那么.event IL部分是什么意思? [英] If events are implemented as delegates in .NET, what is the point of the .event IL section?

查看:170
本文介绍了如果事件在.NET中作为代理实现,那么.event IL部分是什么意思?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经看到有关Stack Overflow的一些非常好的问题,涉及到这两个功能的代理,事件和.NET的实现。一个问题,特别是 C#活动如何在幕后工作?,产生了一个很好的答案,很好地解释了一些微妙的点。



上述问题的答案是这样的:


当你声明一个类似字段的事件
...编译器生成方法
和一个私有字段(与委托相同类型
)。当您引用ElementAddedEvent
时,您可以在该类中
。在
之外,您是指
字段


从同一问题链接的MSDN文章( Field-like events )补充说:


提出事件的概念是
,正好相当于调用事件代表的
代表 -
,没有特殊的语言
构建用于提升事件。


想要进一步检查,我建立了一个测试项目,以便查看事件和委托编译的IL:

  public class TestClass 
{
public EventHandler处理程序
public event EventHandler FooEvent;

public TestClass()
{}
}

我预期委托字段处理程序和事件 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
{
//构造函数IL隐藏
}

.field私有类[mscorlib] System.EventHandler FooEvent
.field public class [mscorlib] System.EventHandler handler
}

由于事件只不过是使用编译器生成的代理添加删除方法,我并没有期望看到事件被视为比IL更多的事情。但是添加和删除方法是在开始 .event 而不是 .method 的部分中定义的。



我的最终问题是:如果事件只是使用访问者方法的代理实现,那么有一个 .event IL部分?不能通过使用 .method 部分在IL中实现它们吗?是 .event 相当于 .method

解决方案

我不确定这是令人惊讶的...与属性vs字段相同(因为相同之前的属性函数作为事件:通过访问器封装):

  .field public string Foo // public field 
.property instance string Bar // public property
{
.get instance string MyType :: get_Bar()
.set instance void MyType :: set_Bar(string)
}

另外 - 事件不要提及关于字段的任何内容;他们定义访问者(添加/删除)。代表支持者是一个实现细节;它只是这样发生,field-like-events将一个字段声明为一个支持成员 - 与自动实现的属性声明一个字段作为支持成员的方式相同。其他实现是可能的(非常普遍,特别是在表单等)。



其他常见的实现:



稀疏 - 事件(控件等) - EventHandlerList(或类似):

  //只有一个实例字段,无论事件多少; 
//如果我们期望大多数事件被取消订阅,非常有用
private EventHandlerList events = new EventHandlerList();
protected EventHandlerList Events {
get {return events; } //通常lazy
}

//每个事件重复这个代码
private static readonly object FooEvent = new object();
public event EventHandler Foo
{
add {Events.AddHandler(FooEvent,value); }
remove {Events.RemoveHandler(FooEvent,value);
}
protected virtual void OnFoo()
{
EventHandler handler = Events [FooEvent] as EventHandler;
if(handler!= null)handler(this,EventArgs.Empty);
}

(以上几乎是win-forms事件的骨干) / p>

Facade(虽然这会使发件人有点混乱;一些中介代码通常是有帮助的):

  private bar wrappedObject; // via ctor 
public event EventHandler SomeEvent
{
add {wrappedObject.SomeOtherEvent + = value; }
删除{wrappedObject.SomeOtherEvent - = value; }
}

(以上也可用于有效地重命名事件) p>

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?

解决方案

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):

.field public string Foo // public field
.property instance string Bar // public property
{
    .get instance string MyType::get_Bar()
    .set instance void MyType::set_Bar(string)
}

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):

// only one instance field no matter how many events;
// very useful if we expect most events to be unsubscribed
private EventHandlerList events = new EventHandlerList();
protected EventHandlerList Events {
    get { return events; } // usually lazy
}

// this code repeated per event
private static readonly object FooEvent = new object();
public event EventHandler Foo
{
    add { Events.AddHandler(FooEvent, value); }
    remove { Events.RemoveHandler(FooEvent, value); }
}
protected virtual void OnFoo()
{
    EventHandler handler = Events[FooEvent] as EventHandler;
    if (handler != null) handler(this, EventArgs.Empty);
}

(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):

private Bar wrappedObject; // via ctor
public event EventHandler SomeEvent
{
    add { wrappedObject.SomeOtherEvent += value; }
    remove { wrappedObject.SomeOtherEvent -= value; }
}

(the above can also be used to effectively rename an event)

这篇关于如果事件在.NET中作为代理实现,那么.event IL部分是什么意思?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆