这是我参与 11 月更文挑战的第 25 天,活动详情查看:2021 最后一次更文挑战
事件
事件不是委托类型的字段。 C#提供了一种简写方式,允许使用字段风格的事件(field-like event)。
将事件看做类似于属性(property)的东西是很有好处的。声明为具有一种特定的类型。
事件必须是一个委托类型。
使用属性时,感觉就像是直接对它的字段进行取值和赋值,但实际是在调用方法,也就是取值方法和赋值方法。取值方法也可以说成是get accessor或者获取方法;而赋值方法也可以说成是set accessor或者设置方法。
实现属性时,可以在那些方法中做任何事情。 大多数属性都只是实现了简单的字段,有时会在赋值方法中添加一些校验机制,有时则会添加一些线程安全性。
在订阅或取消订阅一个事件时,看起来就像是在通过+=和-=运算符使用委托类型的字段。但和属性的情况一样,这个过程实际是在调用方法(add和remove方法)
字段风格的事件使所有这些的实现变得更易阅读,只需一个声明就可以了。
编译器会将声明转换成一个具有默认add/remove实现的事件和一个私有委托类型的字段。
类内的代码能看见字段;类外的代码只能看见事件。这样一来,表面上似乎能调用一个事件,但为了调用事件处理程序,实际做的事情是调用存储在字段中的委托实例。
Delegates and Events
委托类型有成员从其父级类型继承,一个构造器具有参数和三个额外的方法
public string Invoke (int x);
public System.IAsyncResult BeginInvoke(int x, System.AsyncCallback callback, object state);
public string EndInvoke(IAsyncResult result);
复制代码
在c#中,事件处理程序的调用不是事件本身的一部分。添加和删除方法在c#中使用eventName += delegateInstance; 和eventName -= delegateInstance;其中eventName可以通过引用(例如myForm.Click)或类型名(例如MyClass.SomeEvent)来限定。
// field-like event
public event EventHandler MyEvent;
// 在类型本身(包括嵌套类型)的文本中,编译器会生成引用委托变量( _myEvent)的代码。在所有其他上下文中,编译器生成引用该事件的代码。
// 对事件的访问由事件声明决定,但委托变量始终是私有的。
// 事件的隐式主体显然是向委托变量添加/删除委托实例的主体,但更改是在锁内进行的。
private EventHandler _myEvent;
public event EventHandler MyEvent
{
add
{
lock (this)
{
_myEvent += value;
}
}
remove
{
lock (this)
{
_myEvent -= value;
}
}
}
复制代码
事件是对委托实现了封装。对事件的订阅和取消订阅进行了封装,不允许对事件处理程序列表进行任意访问,语言可以通过提供声明和订阅的语法使事情变得更简单。
总结
委托提供了一种简单的方法来表示方法调用(可能使用目标对象),将其作为可传递的数据块。它们是事件的基础,事件是在适当的时候添加和删除要调用的处理程序代码的有效约定。
- 委托封装了包含特殊返回类型和一组参数的行为,类似包含单一方法的接口;
- 委托类型声明中所描述的类型签名决定了哪个方法可用于创建委托实例,同时决定了调用的签名;
- 为了创建委托实例,需要一个方法以及(对于实例方法来说)调用方法的目标;
- 委托实例是不易变的;
- 每个委托实例都包含一个调用列表——一个操作列表;
- 委托实例可以合并到一起,也可以从一个委托实例中删除另一个;
- 事件不是委托实例——只是成对的add/remove方法(类似于属性的取值方法/赋值方法)。




近期评论