C#中的委托和事件学习(续)
1、将NumberChanged声明为委托变量还是事件都无所谓了,因为它是私有的,即便将它声明为一个委托变量,客户端也看不到它,也就无法通过它来触发事件、调用订阅者的方法。而只能通过Register()和UnRegister()方法来注册和取消注册,通过调用DoSomething()方法触发事件(而不是NumberChanged本身,这在前面已经讨论过了)。 2、我们还应该发现,这里采用的、对NumberChanged委托变量的访问模式和C#中的属性是多么类似啊?大家知道,在C#中通常一个属性对应一个类型成员,而在类型的外部对成员的操作全部通过属性来完成。尽管这里对委托变量的处理是类似的效果,但却使用了两个方法来进行模拟,有没有办法像使用属性一样来完成上面的例子呢?答案是有的,C#中提供了一种叫事件访问器(Event Accessor)的东西,它用来封装委托变量。如下面例子所示: class Program { static void Main(string[] args) { Publishser pub = new Publishser(); Subscriber1 sub1 = new Subscriber1(); Subscriber2 sub2 = new Subscriber2(); pub.NumberChanged -= sub1.OnNumberChanged; // 不会有任何反应 pub.NumberChanged += sub2.OnNumberChanged; // 注册了sub2 pub.NumberChanged += sub1.OnNumberChanged; // sub1将sub2的覆盖掉了 pub.DoSomething(); // 触发事件 } } // 定义委托 public delegate string GeneralEventHandler(); // 定义事件发布者 public class Publishser { // 声明一个委托变量 private GeneralEventHandler numberChanged; // 事件访问器的定义 public event GeneralEventHandler NumberChanged { add { numberChanged = value; } remove { numberChanged -= value; } } public void DoSomething() { // 做某些其他的事情 if (numberChanged != null) { // 通过委托变量触发事件 string rtn = numberChanged(); Console.WriteLine("Return: {0}", rtn); // 打印返回的字符串 } } } // 定义事件订阅者 public class Subscriber1 { public string OnNumberChanged() { Console.WriteLine("Subscriber1 Invoked!"); return "Subscriber1"; } } public class Subscriber2 {/* 与上类同,略 */} public class Subscriber3 {/* 与上类同,略 */} 上面代码中类似属性的public event GeneralEventHandler NumberChanged {add{...}remove{...}}语句便是事件访问器。使用了事件访问器以后,在DoSomething方法中便只能通过numberChanged委托变量来触发事件,而不能NumberChanged事件访问器(注意它们的大小写不同)触发,它只用于注册和取消注册。下面是代码输出: 复制代码 代码如下:
获得多个返回值与异常处理 现在假设我们想要获得多个订阅者的返回值,以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 {与上面类同,略} 如果运行上面的代码,可以得到这样的输出: 复制代码 代码如下: (编辑:焦作站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |