您的位置:首页 > 编程语言 > C#

C#深入学习 之 委托和事件

2010-03-20 23:22 387 查看
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

}


宇宙中的幸福
  彼得、他的老板和宇宙最终都满足了。彼得的老板和宇宙可以收到他们感兴趣的事件通知,减少了实现的负担和非必需的往返“差旅费”。彼得可以通知他们,而不管他们要花多长时间来从目的方法中返回,同时又可以异步地得到他的结果。彼得知道,这并不*十分*简单,因为当他异步激发事件时,方法要在另外一个线程中执行,彼得的目的方法完成的通知也是一样的道理。但是,迈克和彼得是好朋友,他很熟悉线程的事情,可以在这个领域提供指导。
  他们永远幸福地生活下去……<完>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: