C# 之委托和事件

委托

主要几个问题

  • 什么是委托
  • 怎么用
  • 什么是事件
  • 怎么用

委托是什么

委托,相当于在类中声明了一个方法类型,
委托的主要一个应用就是,发布 - 订阅
比如:

// 发布者,感温器类,温度改变后,调用订阅者的订阅方法
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 {}

这样去声明了一个委托的事件之后,就是声明这个委托是一个事件(事实上,声明了之后,编译之后会生成一些限制代码)
会有两个作用:

  1. 禁止对一个public委托使用赋值运算符
  2. 不允许包容类以外的类调用委托
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值