1.什么是委托?
委托是表示方法的类型。
2.定义委托
Delegate int Del(int a); //定义委托
//定义委托实例 Del del; //Del类型的委托 EventHandle handle; //void(object,EventArgs)类型的委托 Action action; //void()类型的委托 Action<int> action; //泛型委托 void(int)类型的委托 Func<int> func; //泛型委托 int()类型的委托 Func<int,string> func; //泛型委托 int(string)类型的委托
3.执行委托
//同步执行,会阻塞线程 action(args); action.Invoke(args); //异步执行,不会阻塞线程 action.BeginInvoke(args); //EndInvoke(agrs)返回委托执行结果,但是会等待,可通过传入回调函数的方法解决等待问题。
4.什么是事件?
事件是对委托的封装,类似于private的委托,但在类外部可以使用+=方法注册事件。
事件的出现可以降低程序的耦合度,事件理应由事件拥有者触发,而public的委托可以在类的外部被调用者触发,事件的特性是能在外部注册,不能触发。
事件的写法就是在委托前加event关键字
public event Del del; public event Action<int> action; public EventHandle<MyEventArgs> Handle;
5.单播委托
只注册了一个方法,使用=赋值。
Action action = Method; //注册委托 action.Invoke(); //同步执行 action.beginInvoke(args); //异步执行
6.多播委托
有多个注册方法,使用=/+=注册。
Action action = Method1; //注册 Action action += Method2; //注册 action.Invoke(); //同步执行Method1和Method2 action.BeginInvoke(args); //异步执行会报错 //正确的异步执行多播委托方法 if(action != null) { Delegete[] list = action.GetInvocationList(); //返回注册列表 foreach(Delegate del in list) { Action ac = (Action)del; ac.BeginInvoke(args); } }
7.带有返回值的委托
①单播委托
action.Invoke()同步执行,
IAsyncResult ar = action.BeginInvoke(args)异步执行
int re = action.EndInvoke(ar)得到结果
②多播委托
会返回最后一个委托的值,可通过遍历委托列表解决
使用GetInvocationList()方法获得委托列表
8.如何让事件只允许一个方法注册
解决方法是:将事件写成private,再写一个public的注册方法(使用 = 注册),一个public的取消注册方法(使用 -= 取消注册)
private event Action action; public void Register(Action ac) { action = ac; //=是关键,覆盖注册 } pub void UnRegister(Action ac) { action -= ac; }
9.注册方法(订阅者)执行出现异常怎么处理
采用try-catch捕获,并用GetInvocationList()获取委托列表分开执行,这样可以保证在一个异常出现时,不回影响其它订阅方法的执行。
//触发事件的方法 void Method() { if(action != null) { Delegate[] dels = action.GetInvocationList(); foreach(var del in dels) { try { ...执行委托 } catch(..){}
//这里可以使用同步执行或者异步执行
//异步执行时,只有在调用EndInvoke方法后才会抛出异常。
} } }