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方法后才会抛出异常。
}
}
}