主要几个问题
委托,相当于在类中声明了一个方法类型,
委托的主要一个应用就是,发布 - 订阅
比如:
// 发布者,感温器类,温度改变后,调用订阅者的订阅方法
class Thermostat{
....
// 当温度改变时,调用的委托
public delegate void TemperatureChangeHandler(float newTemperature)
// 相当于发布方法
public void onCurrent(float current){
// 改变当前温度
// 并且调用委托
TemperatureChangeHandler(current);
}
....
}
如上例子,相当于声明了一个参数为float
类型,返回值为void
的一个方法。
再写一个类,用于给Thermostat
类的委托方法赋值。
// 订阅者,冷却器
class Cooler{
....
// 订阅方法,也就是发布者发布时,调用的订阅者的订阅方法
public void onChanged(float tem){
console.write("onChanged");
}
....
}
Cooler cooler = new Cooler();
Thermostat thermostat = new Thermostat();
// 将cooler的订阅方法,注册到委托方法中
thermostat.TemperatureChangeHandler +=cooler.onChanged
thermostat.TemperatureChangeHandler +=cooler.onChanged
thermostat.TemperatureChangeHandler +=cooler.onChanged thermostat.TemperatureChangeHandler +=cooler.onChanged
如此编码,便会形成一个委托的方法链,当发布者调用委托方法时,就会执行迭代地执行委托链中的订阅方法。
Cooler cooler1 = new Cooler();
Cooler cooler2 = new Cooler();
Thermostat thermostat = new Thermostat();
// 将cooler的订阅方法,注册到委托方法中
thermostat.TemperatureChangeHandler +=cooler1 .onChanged
thermostat.TemperatureChangeHandler +=cooler2.onChanged
thermostat.onCurrent(15);
// 如果要移出一个方法
thermostat -=cooler1.onChanged
以上为不规范编码,切勿直接复制到编辑器,仅做例子。
两个重点
+=
对委托方法赋值,多个方法形成委托链,如果使用 =
那么会对委托进行覆盖。假如委托链中的一个订阅方法引发了异常,那么链中的后续订阅方法就不能得到执行了,我们需要对委托方法进行异常的捕获,以使后续方法正常执行。
// 如在发布者的发布方法中
public delegate void OnChangedHandler(float tem)
public void publish(float tem){
// 可通过委托的GetInvocationList()去获取委托链
foreach(OnChangedHandler handler in OnChangedHandler.GetInvocationList()){
// 捕获
try{
handler(tem)
}catch(Exception e){
....
}
}
}
我们需要和处理异常的方法一致,需要调用委托的GetInvocationList方法来获取委托链。
为何会有event
事件?
比如
// 一个感温器类
class Thermostat{
// 委托方法
public delegate void TemperatureChangeHandler(float newTemperature)
private float _Current;
// 修改/获取感温器当前温度
public float Current(float current){
// 改变当前温度
// 并且调用委托
get{
return _Current;
}
set{
// 调用委托,发布通知到订阅者
TemperatureChangeHandler(value);
// 修改感温器的温度
_Current = value;
}
}
}
// 在main函数中
static void Main(string[] args)
{
// 创建对象,注册订阅方法,省略
....
// 调用委托
Thermostat.TemperatureChangeHandler(123);
}
如果,我们可以直接在感温器类的外部直接调用委托方法机进行通知,而不是调用感温器类的Current
方法去修改感温器类的温度,然后再调用委托发送通知。那么这样直接在外部调用委托方法,所导致的就是,感温器的温度并没有被改变,但是却发送了通知给所有的订阅者。
并且,并且
我们可以直接在外部使用 =
,+=
和-=
对委托进行修改。
这两个问题都是委托的封装不充分的体现。
public delegate void TemperatureChangeHandler(float tem);
public event TemperatureChangeHandler onTemperatureChange = delegate {}
这样去声明了一个委托的事件之后,就是声明这个委托是一个事件(事实上,声明了之后,编译之后会生成一些限制代码)
会有两个作用: