C#中的委托和事件学习(续)

2019-05-12 07:23:05王冬梅

上面代码中类似属性的public event GeneralEventHandler NumberChanged {add{...}remove{...}}语句便是事件访问器。使用了事件访问器以后,在DoSomething方法中便只能通过numberChanged委托变量来触发事件,而不能NumberChanged事件访问器(注意它们的大小写不同)触发,它只用于注册和取消注册。下面是代码输出:


Subscriber1 Invoked!
Return: Subscriber1

获得多个返回值与异常处理

现在假设我们想要获得多个订阅者的返回值,以List<string>的形式返回,该如何做呢?我们应该记得委托定义在编译时会生成一个继承自MulticastDelegate的类,而这个MulticastDelegate又继承自Delegate,在Delegate内部,维护了一个委托链表,链表上的每一个元素,为一个只包含一个目标方法的委托对象。而通过Delegate基类的GetInvocationList()静态方法,可以获得这个委托链表。随后我们遍历这个链表,通过链表中的每个委托对象来调用方法,这样就可以分别获得每个方法的返回值:

class Program4 {
   static void Main(string[] args) {
     Publishser pub = new Publishser();
     Subscriber1 sub1 = new Subscriber1();
     Subscriber2 sub2 = new Subscriber2();
     Subscriber3 sub3 = new Subscriber3();

     pub.NumberChanged += new DemoEventHandler(sub1.OnNumberChanged);
     pub.NumberChanged += new DemoEventHandler(sub2.OnNumberChanged);
     pub.NumberChanged += new DemoEventHandler(sub3.OnNumberChanged);

     List<string> list = pub.DoSomething(); //调用方法,在方法内触发事件

    foreach (string str in list) {
       Console.WriteLine(str);
     }      
   }
 }

public delegate string DemoEventHandler(int num);

// 定义事件发布者
public class Publishser {
   public event DemoEventHandler NumberChanged;  // 声明一个事件

  public List<string> DoSomething() {
     // 做某些其他的事

    List<string> strList = new List<string>();
     if (NumberChanged == null) return strList;

     // 获得委托数组
    Delegate[] delArray = NumberChanged.GetInvocationList();

     foreach (Delegate del in delArray) {
       // 进行一个向下转换
      DemoEventHandler method = (DemoEventHandler)del;
       strList.Add(method(100));    // 调用方法并获取返回值
    }
     
     return strList;
   }
 }

// 定义事件订阅者
public class Subscriber1 {
   public string OnNumberChanged(int num) {
     Console.WriteLine("Subscriber1 invoked, number:{0}", num);
     return "[Subscriber1 returned]";
   }
 }
public class Subscriber3 {与上面类同,略}
public class Subscriber3 {与上面类同,略}

如果运行上面的代码,可以得到这样的输出:

Subscriber1 invoked, number:100
Subscriber2 invoked, number:100
Subscriber3 invoked, number:100
[Subscriber1 returned]
[Subscriber2 returned]
[Subscriber3 returned]