委托与事件

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

  

原文地址:https://www.cnblogs.com/lztwj/p/5369687.html