using System; namespace ConsoleApplication1 { #region P1 / <summary> / 从前,在南方一块奇异的土地上,有个工人名叫彼得,他非常勤奋, / 对他的老板总是百依百顺。但是他的老板是个吝啬的人,从不信任别人, / 坚决要求随时知道彼得的工作进度,以防止他偷懒。但是彼得又不想让 / 老板呆在他的办公室里站在背后盯着他,于是就对老板做出承诺:无论 / 何时,只要我的工作取得了一点进展我都会及时让你知道。彼得通过周 / 期性地使用“带类型的引用”(原文为:“typed reference” 也就是 / delegate??)“回调”他的老板来实现他的承诺,如下 / </summary> //class Worker //{ // private Boss _boss; // public void Advise(Boss boss) { _boss = boss; } // public void DoWork() // { // Console.WriteLine("工作: 工作开始"); // if (_boss != null) _boss.WorkStarted(); // Console.WriteLine("工作: 工作进行中"); // if (_boss != null) _boss.WorkProgressing(); // Console.WriteLine("工作: 工作完成"); // if (_boss != null) // { // int grade = _boss.WorkCompleted(); // Console.WriteLine("工人的工作得分=" + grade); // } // } //} //class Boss //{ // public void WorkStarted() { /* 老板不关心。 */ } // public void WorkProgressing() { /*老板不关心。 */ } // public int WorkCompleted() // { // Console.WriteLine("时间差不多!"); // return 2; /* 总分为10 */ // } //} //class Universe //{ // static void Main() // { // Worker peter = new Worker(); // Boss boss = new Boss(); // peter.Advise(boss); // peter.DoWork(); // Console.WriteLine("Main: 工人工作完成"); // Console.ReadLine(); // } //} #endregion #region P2 / <summary> / 现在,彼得成了一个特殊的人, / 他不但能容忍吝啬的老板,而 / 且和他周围的宇宙也有了密切的联系, / 以至于他认为宇宙对他的工作进度也感兴趣。 / 不幸的是,他必须也给宇宙添加一个特殊的 / 回调函数Advise来实现同时向他老板和宇宙 / 报告工作进度。彼得想要把潜在的通知的列 / 表和这些通知的实现方法分离开来,于是他 / 决定把方法分离为一个接口 / </summary> //public interface IWorkerEvents //{ // void WorkStarted(); // void WorkProgressing(); // int WorkCompleted(); //} //public class Worker //{ // public void Advise(IWorkerEvents events) // { // this._events = events; // } // public void DoWork() // { // Console.WriteLine("工作:工作开始"); // if (_events != null) // { // _events.WorkStarted(); // } // Console.WriteLine("工作:工作进行中"); // if (_events != null) // { // _events.WorkProgressing(); // } // Console.WriteLine("工作:工作完成"); // if (_events != null) // { // int grade = _events.WorkCompleted(); // Console.WriteLine("工人的工作得分={0}", grade); // } // } // private IWorkerEvents _events; //} //public class Boss : IWorkerEvents //{ // #region IWorkerEvents Members // public void WorkStarted() // { // //throw new NotImplementedException(); // } // public void WorkProgressing() // { // //throw new NotImplementedException(); // } // public int WorkCompleted() // { // return 5; // } // #endregion //} //public class Universe : IWorkerEvents //{ // #region IWorkerEvents Members // public void WorkStarted() // { // // throw new NotImplementedException(); // } // public void WorkProgressing() // { // //throw new NotImplementedException(); // } // public int WorkCompleted() // { // //throw new NotImplementedException(); // return 8; // } // #endregion //} //public class Programme //{ // static void Main() // { // Worker worker = new Worker(); // worker.Advise(new Boss()); // worker.DoWork(); // worker.Advise(new Universe()); // worker.DoWork();//由此可见无法同时通知宇宙和老板 // Console.ReadLine(); // } //} #endregion #region P3 // delegate void WorkStarted(); // delegate void WorkProgress(); // delegate int WorkCompleted(); // /// <summary> // /// 他的老板还是抱怨得很厉害。“彼得!”他老板吼道,“你为什么在工作一开始和工作进行中都来烦我?!我不关心这些事件。你不但强迫我实现了这些方法,而且还在浪费我宝贵的工作时间来处理你的事件,特别是当我外出的时候更是如此!你能不能不再来烦我?” /于是,彼得意识到接口虽然在很多情况都很有用,但是当用作事件时,“粒度”不够好。他希望能够仅在别人想要时才通知他们,于是他决定把接口的方法分离为单独的委托,每个委托都像一个小的接口方法: // /// </summary> // class Worker // { // public void DoWork() // { // Console.WriteLine("工作:工作开始"); // if (started != null) // { // started(); // } // Console.WriteLine("工作:工作进行中"); // if (progressing != null) // { // progressing(); // } // Console.WriteLine("工作:工作完成"); // if (completed != null) // { // int grade = completed(); // Console.WriteLine("工人的工作得分={0}", grade); // } // } // public WorkCompleted completed; // public WorkProgress progressing; // public WorkStarted started; // } // class Boss // { // public int WorkComplete() // { // Console.WriteLine("Better..."); // return 4; // } // public void WorkProgressing() // { // Console.WriteLine("okok,i am boss"); // } // } // class Universe // { // static void Main() // { // Worker worker = new Worker(); // Boss b = new Boss(); // Universe u = new Universe(); // worker.progressing = new WorkProgress(u.WorkProgressMethod); // worker.progressing += new WorkProgress(b.WorkProgressing); // worker.completed = new WorkCompleted(b.WorkComplete); // worker.DoWork(); // Console.ReadLine(); // } // public void WorkProgressMethod() // { // Console.WriteLine("okok,i am universe..."); // } // } #endregion #region P4 / <summary> / 这样,彼得不会再拿他老板不想要的事件来烦他老板了, / 但是他还没有把宇宙放到他的监听者列表中。因为宇宙是 / 个包涵一切的实体,看来不适合使用实例方法的委托(想 / 像一下,实例化一个“宇宙”要花费多少资源…..),于 / 是彼得就需要能够对静态委托进行挂钩,委托对这一点支持得很好 / </summary> //class Universe //{ // static void WorkerStartedWork() // { // Console.WriteLine("Universe notices worker starting work"); // } // static int WorkerCompletedWork() // { // Console.WriteLine("Universe pleased with worker's work"); // return 7; // } // static void Main() // { // Worker peter = new Worker(); // Boss boss = new Boss(); // peter.completed = new WorkCompleted(boss.WorkCompleted); // peter.started = new WorkStarted(Universe.WorkerStartedWork); // peter.completed = new WorkCompleted(Universe.WorkerCompletedWork); // peter.DoWork(); // Console.WriteLine("Main: 工人工作完成"); // Console.ReadLine(); // } //} #endregion #region P5 事件 // // 不幸的是,宇宙太忙了, //也不习惯时刻关注它里面的个体,它可以用自己的委托替换了彼得老板的委托。这是把彼得的Worker类的的委托字段做成public的一个无意识的副作用。同样,如果彼得的老板不耐烦了,也可以决定自己来激发彼得的委托(真是一个粗鲁的老板): Peter's boss taking matters into his own hands //if( peter.completed != null ) peter.completed(); // 彼得不想让这些事发生,他意识到需要给每个委托提供“注册”和“反注册”功能,这样监听者就可以自己添加和移除委托,但同时又不能清空整个列表也不能随意激发彼得的事件了。彼得并没有来自己实现这些功能,相反,他使用了event关键字让C#编译器为他构建这些方法: //class Worker { //... // public event WorkStarted started; // public event WorkProgressing progressing; // public event WorkCompleted completed; //} // 彼得知道event关键字在委托的外边包装了一个property,仅让C#客户通过+= 和 -=操作符来添加和移除,强迫他的老板和宇宙正确地使用事件。 //static void Main() { // Worker peter = new Worker(); // Boss boss = new Boss(); // peter.completed += new WorkCompleted(boss.WorkCompleted); // peter.started += new WorkStarted(Universe.WorkerStartedWork); // peter.completed += new WorkCompleted(Universe.WorkerCompletedWork); // peter.DoWork(); // Console.WriteLine(“Main: 工人工作完成”); // Console.ReadLine(); //} #endregion #region P6 收获所有结果 //delegate void WorkStarted(); //delegate void WorkProgress(); //delegate int WorkCompleted(); / <summary> / 他的老板还是抱怨得很厉害。“彼得!”他老板吼道, / “你为什么在工作一开始和工作进行中都来烦我?! / 我不关心这些事件。你不但强迫我实现了这些方法, / 而且还在浪费我宝贵的工作时间来处理你的事件,特别 / 是当我外出的时候更是如此!你能不能不再来烦我?” /于是,彼得意识到接口虽然在很多情况都很有用,但是当 /用作事件时,“粒度”不够好。他希望能够仅在别人想要 /时才通知他们,于是他决定把接口的方法分离为单独的委 /托,每个委托都像一个小的接口方法: / </summary> //class Worker //{ // public void DoWork() // { // Console.WriteLine("工作:工作开始"); // if (started != null) // { // started(); // } // Console.WriteLine("工作:工作进行中"); // if (progressing != null) // { // progressing(); // } // Console.WriteLine("工作:工作完成"); // if (completed != null) // { // int grade = completed(); // Console.WriteLine("工人的工作得分={0}", grade); // } // Console.WriteLine("下面是所有监听者的情况:"); // if (completed != null) // { // foreach (WorkCompleted wc in completed.GetInvocationList())//收获所有结果 // { // Console.WriteLine("{0}", wc()); // } // } // } // public event WorkCompleted completed; // public event WorkProgress progressing; // public event WorkStarted started; //} //class Boss //{ // public int WorkComplete() // { // Console.WriteLine("Better..."); // return 4; // } // public void WorkProgressing() // { // Console.WriteLine("okok,i am boss"); // } //} //class Universe //{ // static void Main() // { // Worker worker = new Worker(); // Boss b = new Boss(); // Universe u = new Universe(); // worker.completed += new WorkCompleted(b.WorkComplete); // worker.completed += new WorkCompleted(u.WorkCompletedMethod); // worker.DoWork(); // Console.ReadLine(); // } // public int WorkCompletedMethod() // { // Console.WriteLine("okok,i am universe..."); // return 8; // } //} #endregion #region F7 异步通知&忘掉 delegate void WorkStarted(); delegate void WorkProgress(); delegate int WorkCompleted(); /// <summary> /// 同时,他的老板和宇宙还要忙于处理其他事情, /// 也就是说他们给彼得打分所花费的事件变得非常长: /// 很不幸,彼得每次通知一个监听者后必须等待它给 /// 自己打分,现在这些通知花费了他太多的工作事件。 /// 于是他决定忘掉分数,仅仅异步激发事件 /// </summary> class Worker { public void DoWork() { Console.WriteLine("工作:工作开始"); if (started != null) { started(); } Console.WriteLine("工作:工作进行中"); if (progressing != null) { progressing(); } Console.WriteLine("工作:工作完成"); //if (completed != null) //{ // int grade = completed(); // Console.WriteLine("工人的工作得分={0}", grade); //} //Console.WriteLine("下面是所有监听者的情况:"); if (completed != null) { foreach (WorkCompleted wc in completed.GetInvocationList())//收获所有结果 { //wc.BeginInvoke(null, null);//如果不需要返回结果 //Console.WriteLine("{0}", wc()); //IAsyncResult res = wc.BeginInvoke(null, null);//需要返回结果 //while (!res.IsCompleted)//轮询,等待获取结果 //{ // System.Threading.Thread.Sleep(1); // int grade = wc.EndInvoke(res); // Console.WriteLine("工人的工作得分={0}", grade); //} wc.BeginInvoke(new AsyncCallback(WorkGraded), wc);//异步通知:委托 } } Console.WriteLine("Do other thing"); } void WorkGraded(IAsyncResult res) { WorkCompleted wc = res.AsyncState as WorkCompleted; int grade = wc.EndInvoke(res); Console.WriteLine("得到工人的工作得分={0}", grade); } public event WorkCompleted completed; public event WorkProgress progressing; public event WorkStarted started; } class Boss { public int WorkComplete() { System.Threading.Thread.Sleep(3000); Console.WriteLine("okok,i am boss..."); return 4; } } class Universe { static void Main() { Worker worker = new Worker(); Boss b = new Boss(); Universe u = new Universe(); worker.completed += new WorkCompleted(b.WorkComplete); worker.completed += new WorkCompleted(u.WorkCompletedMethod); worker.DoWork(); Console.ReadLine(); } public int WorkCompletedMethod() { System.Threading.Thread.Sleep(4000); Console.WriteLine("okok,i am universe..."); return 8; } } #endregion }
宇宙中的幸福
彼得、他的老板和宇宙最终都满足了。彼得的老板和宇宙可以收到他们感兴趣的事件通知,减少了实现的负担和非必需的往返“差旅费”。彼得可以通知他们,而不管他们要花多长时间来从目的方法中返回,同时又可以异步地得到他的结果。彼得知道,这并不*十分*简单,因为当他异步激发事件时,方法要在另外一个线程中执行,彼得的目的方法完成的通知也是一样的道理。但是,迈克和彼得是好朋友,他很熟悉线程的事情,可以在这个领域提供指导。
他们永远幸福地生活下去……<完>