September 27, 2023

委托和事件

委托

委托类型是一种类是一个引用类型的数据结构,委托类型的实例可以存储一个或多个方法的引用,或者说是封装一个或多个方法,通过委托实例,可以间接的调用这些封装的方法,但是所存储的方法的参数列表与返回值类型要与对应的委托类型相同,即类型兼容

委托的缺点

人为失误造成重置

委托很容易因为人为失误造成委托内部封装的所有方法重置,例如

1
2
3
myDelegate +=Method1;
myDelegate +=Method2;
myDelegate =Method3;//此处因为认为失误 将+=写成=,造成委托内部封装的所有方法重置

内存泄漏

委托会引用一个或多个方法,如果一个方法是实例的方法,则一个委托引用这个方法时,这个方法所属的对象必须在内存中是存在的,这个对象的内存一旦被释放,委托就不能间接调用该对象的方法

Action委托与Func委托

首先可以知道自定义委托类型,通过关键字delegate进行声明,例如

1
public delegate string MyDelegate();

而C#的类库已经为我们准备好了两种委托,即Action委托Func委托(两者都为泛型委托),许多时候我们并不需要使用自定义委托类型,而是直接使用已经定义好的泛型的Action委托和Func委托

不同点

Action委托无返回值,而Func委托有返回值,两者都有参数列表

事件

首先需要明确很重要的一点:事件不是委托实例!事件不是委托实例!事件不是委托实例!
事件是基于委托的,是一种类型成员,他只能使用+=或者-=而不能直接使用=,弥补了委托种因为人为失误造成的重置问题
事件与属性类似,属性是字段的包装器,而事件是委托类型字段的包装器,作用是隐藏委托实例的大部分内容,仅仅暴露了添加移除事件处理器的功能(所以只能使用+=或者-=而不能直接使用=),从而保护委托类型的字段不被外界滥用

事件的两种声明方式

1
public delegate void FooEventHandler(object sender,EventArgs e);//为OnFoo事件声明委托

完整

1
2
3
4
5
6
7
8
9
10
private FooEventHandler fooEventHandler;//声明委托字段,用来存储事件处理器
public event FooEventHandler OnFoo{
add{
fooEventHandler += value;
}
remove{
fooEventHandler -= value;
}
}

简略

事件的简略声明格式会让事件看起来像一个用event修饰的委托类型的字段(FIELD-LIKE),但并不是一个委托类型的字段!!!并不是一个委托类型的字段!!!并不是一个委托类型的字段!!!

1
public event FooEventHandler OnFoo;

在简化的事件的声明格式中,事件所包装的委托类型的字段由编译器自动生成,这样一来,表面上似乎能调用一个事件,但为了调用事件处理程序,实际做的事情是调用存储在字段中的委托实例

事件模型

About this Post

This post is written by Yuan, licensed under CC BY-NC 4.0.

#C#