首页 C#委托与事件

C#委托与事件

举报
开通vip

C#委托与事件null第七讲第七讲委托和事件委托*委托委托是一种类型,即它与class , interface , struct ,enum处于同一级别,而且它是引用类型. 任何委托类型都是system.delegate类的派生类,但不允许从system.delegate类显式派生新类. 可用delegate关键词定义一个委托类型 委托类型用于封装对方法的调用委托*委托定义委托类型[定义委托将要调用的方法的签名] public delegate 返回值类型 类型名称(形参列表);null*实例化委托类型,得到委托对象[确定要调用...

C#委托与事件
null第七讲第七讲委托和事件委托*委托委托是一种类型,即它与class , interface , struct ,enum处于同一级别,而且它是引用类型. 任何委托类型都是system.delegate类的派生类,但不允许从system.delegate类显式派生新类. 可用delegate关键词定义一个委托类型 委托类型用于封装对方法的调用委托*委托定义委托类型[定义委托将要调用的方法的签名] public delegate 返回值类型 类型名称(形参列表);null*实例化委托类型,得到委托对象[确定要调用方法的对象及方法的名称] 委托类型 委托对象 = new 委托类型(对象名.方法名); 调用某类的实例方法 委托类型 委托对象 = new 委托类型(类型名.方法名); 调用某类的静态方法null*调用委托,实现对方法的调用.[给委托对象传参数,得到委托对象的返回值] 委托对象(实参);好处在哪里*好处在哪里调方法的人不必知道方法属于哪个类,方法叫什么名字. 用在哪里? 事件与事件处理程序的关联事件*事件一件事情 对象发生了一件事情或对象的状态发生了变化 人生病了. 按钮被用户点击了. 窗口被关掉了 一个形态的颜色从红色变成蓝色 事件是类对类的使用者发出的一个通知 事件发生后可能要进行一些处理 事件处理程序[方法] 事件与事件处理程序如何关联呢?委托事件*事件事件是类型的成员,本身不是类型 事件的类型是事件定义好的某种委托类型 事件发生时,委托对象会调用相关联的方法,即事件的处理程序.事件*事件在引发事件的类中声明事件[将事件声明为某种委托类型] public event 某委托类型 事件名称 订阅事件:在引发事件的类的使用者[另一个类]给事件赋值,值为委托类型的实例,即一个委托对象,委托实例化时已决定要调哪个方法 引发事件:在引发事件的类中调用委托控件事件及其委托*控件事件及其委托Click , Enter , KeyPress … EventHandler委托*委托Multiply(int,int) { …. } Divide(int,int) { …. } 可以引用任何方法,将在运行时决定委托和方法必须具有相同的签名--- public delegate Call(int num1, int num2); ---定义委托 2-1 *演示:示例 3定义委托 2-1 [访问修饰符] delegate 返回类型 委托名(); 语法class Delegates { public delegate int Call(int num1, int num2); class Math { public int Multiply(int num1, int num2) { // 实现 } public int Divide(int num1, int num2) {// 实现 } } class TestDelegates { static void Main() { Call objCall; Math objMath = new Math(); objCall = new Call(math.Multiply); } }将方法与委托关联起来定义委托 2-2*定义委托 2-2class Delegates { // 委托定义 public delegate int Call(int num1, int num2); class Math { // 乘法方法 public int Multiply(int num1, int num2) { return num1*num2; } // 除法方法 public int Divide(int num1, int num2) { return num1/num2; } }static void Main(string[] args) { // 委托的对象 Call objCall; // Math 类的对象 Math objMath = new Math(); // 将方法与委托关联起来 objCall = new Call(objMath.Multiply); // 将委托实例化 result = objCall(5, 3); System.Console.WriteLine("结果为 {0}", result); } 将方法与委托关联起来事件*事件“请听题~”集中注意力聆听其他人事件源事件的发布者事件的订阅人未订阅该事件 定义事件 为对象订阅该事件 将发生的事件通知给订阅人定义事件*定义事件[访问修饰符] event 委托名 事件名; 语法public delegate void delegateMe(); private event delegateMe eventMe;订阅事件 *订阅事件 eventMe += new delegateMe(objA.Method); eventMe += new delegateMe(objB.Method);通知订阅对象 *通知订阅对象 if(condition) { eventMe(); }调用订阅特定事件的对象的所有委托示例*演示:示例 4示例class TestEvents { [STAThread] static void Main(string[] args) { // 委托的对象 Delegate objDelegate = new Delegate(); // ClassA 的对象 ClassA objClassA = new ClassA(); // ClassB 的对象 ClassB objClassB = new ClassB(); // 订阅该事件 objDelegate.NotifyEveryOne += new Delegate.MeDelegate(objClassA.DispMethod); objDelegate.NotifyEveryOne += new Delegate.MeDelegate(objClassB.DispMethod); objDelegate.Notify(); } }示例*示例class Delegate { // 定义委托 public delegate void MeDelegate(); // 定义事件 public event MeDelegate NotifyEveryOne; public void Notify() { // 如果事件不为 null if(NotifyEveryOne != null) { Console.WriteLine("触发事件:"); // 触发事件 NotifyEveryOne(); } } }示例*示例class ClassA { public void DispMethod() { Console.WriteLine(“Class A 已接到 NotifyEveryOne 事件的通知!"); } } // 第二个类 class ClassB { public void DispMethod() { Console.WriteLine(“Class B 已接到 NotifyEveryOne 事件的通知! "); } } System.EventArgs类System.EventArgs类System.EventArgs类就是我们常说的事件参数类 public class NumberReachedEventArgs : EventArgs {     private int _reached;     public NumberReachedEventArgs(int num)     {         this._reached = num;     }     public int ReachedNumber     {         get         {             return _reached;         }     } } *Net Framework中的委托与事件 Net Framework中的委托与事件 .Net Framework的编码规范: 1.委托类型的名称都应该以EventHandler结束。 2.委托的原型定义:有一个void返回值,并接受两个输入参数:一个Object 类型,一个 EventArgs类型(或继承自EventArgs)。 3.事件的命名为 委托去掉 EventHandler之后剩余的部分。 4.继承自EventArgs的类型应该以EventArgs结尾。 再做一下说明: 1. 委托声明原型中的Object类型的参数代表了Subject,也就是监视对象。 2. EventArgs 对象包含了Observer所感兴趣的数据。*为什么要使用事件而不是委托变量? 为什么要使用事件而不是委托变量? 1.主要是从封装性和易用性上去考虑 2.事件应该由事件发布者触发,而不应该由客户端(客户程序)来触发。 NOTE:注 意这里术语的变化,当我们单独谈论事件,我们说发布者(publisher)、订阅者(subscriber)、客户端(client)。当我们讨论 Observer模式,我们说主题(subject)和观察者(observer)。客户端通常是包含Main()方法的Program类。 class Program {     static void Main(string[] args) {         Publishser pub = new Publishser();         Subscriber sub = new Subscriber();                 pub.NumberChanged += new NumberChangedEventHandler(sub.OnNumberChanged);         pub.DoSomething();          // 应该通过DoSomething()来触发事件         pub.NumberChanged(100);     // 但可以被这样直接调用,对委托变量的不恰当使用     } } // 定义委托 public delegate void NumberChangedEventHandler(int count); *null// 定义事件发布者 public class Publishser {     private int count;     public NumberChangedEventHandler NumberChanged;         // 声明委托变量     //public event NumberChangedEventHandler NumberChanged; // 声明一个事件     public void DoSomething() {         // 在这里完成一些工作 ...         if (NumberChanged != null) {    // 触发事件             count++;             NumberChanged(count);         }     } } // 定义事件订阅者 public class Subscriber {     public void OnNumberChanged(int count) {         Console.WriteLine("Subscriber notified: count = {0}", count);     } }*null上 面代码定义了一个NumberChangedEventHandler委托,然后我们创建了事件的发布者Publisher和订阅者 Subscriber。当使用委托变量时,客户端可以直接通过委托变量触发事件,也就是直接调用pub.NumberChanged(100),这将会影 响到所有注册了该委托的订阅者。而事件的本意应该为在事件发布者在其本身的某个行为中触发,比如说在方法DoSomething()中满足某个条件后触发。通过添加event关键字来发布事件,事件发布者的封装性会更好,事 件仅仅是供其他类型订阅,而客户端不能直接触发事件(语句pub.NumberChanged(100)无法通过编译),事件只能在事件发布者 Publisher类的内部触发(比如在方法pub.DoSomething()中),换言之,就是NumberChanged(100)语句只能在 Publisher内部被调用。 尝试一下,将委托变量的声明那行代码注释掉,然后取消下面事件声明的注释。此时程序是无法 编译的,当你使用了event关键字之后,直接在客户端触发事件这种行为,也就是直接调用pub.NumberChanged(100),是被禁止的。事 件只能通过调用DoSomething()来触发。这样才是事件的本意,事件发布者的封装才会更好。 就好像如果我们要定义一个数字类型,我 们会使用int而不是使用object一样,给予对象过多的能力并不见得是一件好事,应该是越合适越好。尽管直接使用委托变量通常不会有什么问题,但它给 了客户端不应具有的能力,而使用事件,可以限制这一能力,更精确地对类型进行封装。 *为什么委托定义的返回值通常都为void? 为什么委托定义的返回值通常都为void? 因为委托变量可以供多个订阅者注册,如果定义了返回值,那么多个订阅者的方法 都会向发布者返回数值,结果就是后面一个返回的方法值将前面的返回值覆盖掉了,因此,实际上只能获得最后一个方法调用的返回值。除此以外,发布者和订阅者是松耦合的,发布者根本不关心谁订阅了它的事件、为什么要订阅,更别说订阅者的返回值了,所以返回订阅者的方法返回值大多数 情况下根本没有必要。 class Program {     static void Main(string[] args) {         Publishser pub = new Publishser();         Subscriber1 sub1 = new Subscriber1();         Subscriber2 sub2 = new Subscriber2();         Subscriber3 sub3 = new Subscriber3();         pub.NumberChanged += new GeneralEventHandler(sub1.OnNumberChanged);         pub.NumberChanged += new GeneralEventHandler(sub2.OnNumberChanged);         pub.NumberChanged += new GeneralEventHandler(sub3.OnNumberChanged);         pub.DoSomething();          // 触发事件     } } // 定义委托 public delegate string GeneralEventHandler(); *null// 定义事件发布者 public class Publishser {     public event GeneralEventHandler NumberChanged; // 声明一个事件     public void DoSomething() {         if (NumberChanged != null) {    // 触发事件             string rtn = NumberChanged();             Console.WriteLine(rtn);     // 打印返回的字符串,输出为Subscriber3         }     } } // 定义事件订阅者 public class Subscriber1 {      public string OnNumberChanged() {         return "Subscriber1";     } } public class Subscriber2 { /* 略,与上类似,返回Subscriber2*/ } public class Subscriber3 { /* 略,与上类似,返回Subscriber3*/ }*如何让事件只允许一个客户订阅? 如何让事件只允许一个客户订阅? // 定义事件发布者 public class Publishser {     private event GeneralEventHandler NumberChanged;    // 声明一个私有事件     // 注册事件     public void Register(GeneralEventHandler method) {         NumberChanged = method;     }     // 取消注册     public void UnRegister(GeneralEventHandler method) {         NumberChanged -= method;     }     public void DoSomething() {         // 做某些其余的事情         if (NumberChanged != null) {    // 触发事件             string rtn = NumberChanged();             Console.WriteLine("Return: {0}", rtn);       // 打印返回的字符串,输出为Subscriber3         }     } } NOTE:注意上面,在UnRegister()中,没有进行任何判断就使用了NumberChanged-=method语句。这是因为即使method方法没有进行过注册,此行语句也不会有任何问题,不会抛出异常,仅仅是不会产生任何效果而已。注意在Register()方法中,我们使用了赋值操作符“=”,而非“+=”,通过这种方式就避免了多个方法注册。 *事件访问器(Event Accessor)事件访问器(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;         }     } *null    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事件访问器(注意它们的大小写不同)触发,它只用于注册和取消注册。下面是代码输出: Subscriber1 Invoked! Return: Subscriber1 *获得多个返回值与异常处理 获得多个返回值与异常处理 委托定义在编译时会生成一个继承自 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 list = pub.DoSomething();  //调用方法,在方法内触发事件         foreach (string str in list) {             Console.WriteLine(str);         }               } } *nullpublic delegate string DemoEventHandler(int num); // 定义事件发布者 public class Publishser {     public event DemoEventHandler NumberChanged;    // 声明一个事件     public List DoSomething() {         // 做某些其他的事         List strList = new List();         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] *null异常处理 class Program5 {     static void Main(string[] args) {         Publisher pub = new Publisher();         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);     } } public class Publisher {     public event EventHandler MyEvent;     public void DoSomething() {         // 做某些其他的事情         if (MyEvent != null) {             try {                 MyEvent(this, EventArgs.Empty);             } catch (Exception e) {                 Console.WriteLine("Exception: {0}", e.Message);             }         }     } } *nullpublic class Subscriber1 {     public void OnEvent(object sender, EventArgs e) {         Console.WriteLine("Subscriber1 Invoked!");     } } public class Subscriber2 {     public void OnEvent(object sender, EventArgs e) {         throw new Exception("Subscriber2 Failed");     } } public class Subscriber3 {/* 与Subsciber1类同,略*/} 结果是:Subscriber1 Invoked! Exception: Subscriber2 Failed 可以看到,尽管捕获了异常,使得程序没有异常结束,但是却影响到了后面的订阅者,因为Subscriber3也订阅了事件,但是却没有收到事件通知(它的方法没有被调用)。此时,可以先获得委托链表,然后在遍历链表的循环中处理异常。修改一下DoSomething方法: public void DoSomething() {     if (MyEvent != null) {         Delegate[] delArray = MyEvent.GetInvocationList();         foreach (Delegate del in delArray) {             EventHandler method = (EventHandler)del;    // 强制转换为具体的委托类型             try {                 method(this, EventArgs.Empty);             } catch (Exception e) {                 Console.WriteLine("Exception: {0}", e.Message)  } }  }} *DynamicInvoke()方法DynamicInvoke()方法public object DynamicInvoke(params object[] args); 这可能是调用委托最通用的方法了,适用于所有类型的委托。它接受的参数为object[],也就是说它可以将任意数量的任意类型作为参数,并返回单个object对象。上面的DoSomething()方法也可以改写成下面这种通用形式: public void DoSomething() {     // 做某些其他的事情     if (MyEvent != null) {         Delegate[] delArray = MyEvent.GetInvocationList();         foreach (Delegate del in delArray) {                                try {                 // 使用DynamicInvoke方法触发事件                 del.DynamicInvoke(this, EventArgs.Empty);               } catch (Exception e) {                 Console.WriteLine("Exception: {0}", e.Message);             }         }     } } *null注 意现在在DoSomething()方法中,取消了向具体委托类型的向下转换,现在没有了任何的基于特定委托类型的代码,而 DynamicInvoke又可以接受任何类型的参数,且返回一个object对象。所以完全可以将DoSomething()方法抽象出来,使它成 为一个公共方法,然后供其他类来调用。 // 触发某个事件,以列表形式返回所有方法的返回值 public static object[] FireEvent(Delegate del, params object[] args){     List objList = new List();     if (del != null) {         Delegate[] delArray = del.GetInvocationList();         foreach (Delegate method in delArray) {             try {                 // 使用DynamicInvoke方法触发事件                 object obj = method.DynamicInvoke(args);                 if (obj != null)                     objList.Add(obj);             } catch { }         }     }     return objList.ToArray(); } 随后,我们在DoSomething()中只要简单的调用一下这个方法就可以了: public void DoSomething() {     // 做某些其他的事情     Program5.FireEvent(MyEvent, this, EventArgs.Empty); } *委托中订阅者方法超时的处理 委托中订阅者方法超时的处理 订阅者除了可以通过异常的方式来影响发布者以外,还可以通过另一种方式:超时。一般说超时,指的是方法的执行超过某个指定的时间。超时和异常的区别就是超时并不会影响事件的正确触发和程序的正常运行,却会导致事件触发后需要很长才能够结束。在依次执行订阅者的方法这段期间内,客户端程序会被中断,什么也不能做。 因为当执行订阅者方法时(通过委托,相当于依次调用所有注册了的方法),当前线程会转去执行方法中的代码,调用方法的客户端会被中断,只有当方法执行完毕并返回时,控制权才会回到客户端,从而继续执行下面的代码。 class Program6 {     static void Main(string[] args) {         Publisher pub = new Publisher();         Subscriber1 sub1 = new Subscriber1();         Subscriber2 sub2 = new Subscriber2();         Subscriber3 sub3 = new Subscriber3();         pub.MyEvent += new EventHandler(sub1.OnEvent);         pub.MyEvent += new EventHandler(sub2.OnEvent);         pub.MyEvent += new EventHandler(sub3.OnEvent);         pub.DoSomething();      // 触发事件         Console.WriteLine(" Control back to client!"); // 返回控制权     }     *null // 触发某个事件,以列表形式返回所有方法的返回值     public static object[] FireEvent(Delegate del, params object[] args) {         // 代码与上同,略     }} public class Publisher {     public event EventHandler MyEvent;     public void DoSomething() {         // 做某些其他的事情         Console.WriteLine("DoSomething invoked!");         Program6.FireEvent(MyEvent, this, EventArgs.Empty); //触发事件     }} public class Subscriber1 {     public void OnEvent(object sender, EventArgs e) {         Thread.Sleep(TimeSpan.FromSeconds(3));         Console.WriteLine("Waited for 3 seconds, subscriber1 invoked!");     }} public class Subscriber2 {     public void OnEvent(object sender, EventArgs e) {         Console.WriteLine("Subscriber2 immediately Invoked!");     }} public class Subscriber3 {     public void OnEvent(object sender, EventArgs e) {         Thread.Sleep(TimeSpan.FromSeconds(2));         Console.WriteLine("Waited for 2 seconds, subscriber2 invoked!");*null在这段代码中,使用Thread.Sleep()静态方法模拟了方法超时的情况。其中Subscriber1.OnEvent()需要三秒钟完成,Subscriber2.OnEvent()立即执行,Subscriber3.OnEvent需要两秒完成。这段代码完全可以正常输出,也没有异常 抛出(如果有,也仅仅是该订阅者被忽略掉),下面是输出的情况: DoSomething invoked! Waited for 3 seconds, subscriber1 invoked! Subscriber2 immediately Invoked! Waited for 2 seconds, subscriber2 invoked! Control back to client! 但 是这段程序在调用方法DoSomething()、打印了“DoSomething invoked”之后,触发了事件,随后必须等订阅者的三个方法全部执行完毕了之后,也就是大概5秒钟的时间,才能继续执行下面的语句,也就是打印 “Control back to client”。*null如何解决这个问题 委托的定义会生成继承自 MulticastDelegate的完整的类,其中包含Invoke()、BeginInvoke()和EndInvoke()方法。当我们直接调用委 托时,实际上是调用了Invoke()方法,它会中断调用它的客户端,然后在客户端线程上执行所有订阅者的方法(客户端无法继续执行后面代码),最后将控 制权返回客户端。注意到BeginInvoke()、EndInvoke()方法,在.Net中,异步执行的方法通常都会配对出现,并且以Begin和 End作为方法的开头(最常见的可能就是Stream类的BeginRead()和EndRead()方法了)。它们用于方法的异步执行,即是在调用 BeginInvoke()之后,客户端从线程池中抓取一个闲置线程,然后交由这个线程去执行订阅者的方法,而客户端线程则可以继续执行下面的代码。 异步调用来解决订阅者方法执行超时的情况: class Program6 {     static void Main(string[] args) {         Publisher pub = new Publisher();         Subscriber1 sub1 = new Subscriber1();         Subscriber2 sub2 = new Subscriber2();         Subscriber3 sub3 = new Subscriber3();         *null pub.MyEvent += new EventHandler(sub1.OnEvent);         pub.MyEvent += new EventHandler(sub2.OnEvent);         pub.MyEvent += new EventHandler(sub3.OnEvent);         pub.DoSomething();      // 触发事件         Console.WriteLine("Control back to client! "); // 返回控制权         Console.WriteLine("Press any thing to exit...");         Console.ReadKey();      // 暂停客户程序,提供时间供订阅者完成方法     } } public class Publisher {     public event EventHandler MyEvent;     public void DoSomething() {                 // 做某些其他的事情         Console.WriteLine("DoSomething invoked!");         if (MyEvent != null) {             Delegate[] delArray = MyEvent.GetInvocationList();             foreach (Delegate del in delArray) {                 EventHandler method = (EventHandler)del;                 method.BeginInvoke(null, EventArgs.Empty, null, null);             }         }     } } *nullpublic class Subscriber1 {     public void OnEvent(object sender, EventArgs e) {         Thread.Sleep(TimeSpan.FromSeconds(3));      // 模拟耗时三秒才能完成方法         Console.WriteLine("Waited for 3 seconds, subscriber1 invoked!");     } } public class Subscriber2 {     public void OnEvent(object sender, EventArgs e) {         throw new Exception("Subsciber2 Failed");   // 即使抛出异常也不会影响到客户端         //Console.WriteLine("Subscriber2 immediately Invoked!");     } } public class Subscriber3 {     public void OnEvent(object sender, EventArgs e) {         Thread.Sleep(TimeSpan.FromSeconds(2));  // 模拟耗时两秒才能完成方法         Console.WriteLine("Waited for 2 seconds, subscriber3 invoked!");     } } 运行上面的代码,会得到下面的输出: DoSomething invoked! Control back to client! Press any thing to exit... Waited for 2 seconds, subscriber3 invoked! Waited for 3 seconds, subscriber1 invoked!*null注意代码输出中的几个变化: 1.我 们需要在客户端程序中调用Console.ReadKey()方法来暂停客户端,以提供足够的时间来让异步方法去执行完代码,不然的话客户端的程序到此处 便会运行结束,程序会退出,不会看到任何订阅者方法的输出,因为它们根本没来得及执行完毕。原因是这样的:客户端所在的线程我们通常称为主线程,而执行订 阅者方法的线程来自线程池,属于后台线程(Background Thread),当主线程结束时,不论后台线程有没有结束,都会退出程序。(当然还有一种前台线程(Foreground Thread),主线程结束后必须等前台线程也结束后程序才会退出 2.在打 印完“Press any thing to exit...”之后,两个订阅者的方法会以2秒、1秒的间隔显示出来,且尽管我们先注册了subscirber1,但是却先执行了 subscriber3,这是因为执行它需要的时间更短。除此以外,注意到这两个方法是并行执行的,所以执行它们的总时间是最长的方法所需要的时间,也就 是3秒,而不是他们的累加5秒。 3.尽管subscriber2抛出了异常,我们也没有针对异常进行处理,但是客户程序并没有察觉到,程序也没有因此而中断。因为即使抛出异常,也是在另一个线程上,不会影响到客户端线程 *委托和方法的异步调用 委托和方法的异步调用 Net中可以通过委托进行方法的异步调用,就是说客户端在异步调用方法时,本身并不会因为方法的调用而中 断,而是从线程池中抓取一个线程去执行该方法,自身线程(主线程)在完
本文档为【C#委托与事件】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_729035
暂无简介~
格式:ppt
大小:695KB
软件:PowerPoint
页数:0
分类:工学
上传时间:2014-01-26
浏览量:25