委托与事件

来源:互联网 发布:vmware for mac破解版 编辑:程序博客网 时间:2024/06/05 07:34

面向对象编程:生活怎样,编程就怎样。现实世界是个什么样子,编程就是个什么样子。

Visual Studio开发过Windows程序或是Web应用程序的人都该知道事件这一概念,比如最简单的就是单击一个按钮引发按钮的Click事件,而这个事件的添加往往是通过IDE来自动生成,比如对这样一个方法大家应该并不陌生:privatevoidbutton1_Click(object sender,EventArgs e),当我们单击一个按钮的时候,程序会自动执行这个方法中的代码,而且我们可以通过其中的参数获得事件源的一些信息,这样一个效果是怎样做到的呢,下面的内容会帮你解开这些疑问。

我们通过两个场景的模拟来讲解委托与事件。场景如下:

    羊历3513年,青青草原上,羊羊族群已经十分兴旺发达。在羊羊一族里面已经有小镇,有学校,有超市,有美容院,所有羊羊族群的羊都幸福快乐地生活。

    可是,在对岸的森林里,灰太狼带着他的妻子红太狼却对着一群群的肥羊咽着口水。

下面有两个需求场景需要我们来完成。

场景一:这天,喜羊羊,沸羊羊和懒羊羊在草原上吃草。

场景二:灰太狼只要叫一声“哈,我是灰太狼”,喜羊羊,懒羊羊和沸羊羊就说“不好,(灰太)狼来了,快跑!”。

 

 

委托(delegate

委托声明定义一种类型,它用一组特定的参数以及返回类型来封装方法,一旦为委托分配了方法,委托将与该方法具有完全相同的行为。对于静态方法,委托对象封装要调用的方法。对于实例方法,委托对象同时封装一个实例和该实例上的一个方法。

 

注:委托的本质就是一个类,任何可以声明类的地方都可以声明委托。

我们通过场景一的模拟来讲解什么是委托:

 

1  未使用委托的实现方式

 

using System;

using System.Text;

 

namespace 场景一的模拟一

{

    publicdelegate voidEatHandler(string arg);

    classProgram

    {

        staticvoid HappyEat(string food)

        {

            Console.WriteLine("喜羊羊吃{0}",food);

        }

        staticvoid FattyEat(string food)

        {

            Console.WriteLine("懒羊羊吃{0}", food);

        }

        staticvoid ForceEat(string food)

        {

            Console.WriteLine("沸羊羊吃{0}", food);

        }

 

        staticvoid Main(string[] args)

        {

            stringfood ="grass";

 

            EatHandler happyEat =newEatHandler(HappyEat);

            EatHandler fattyEat =newEatHandler(FattyEat);

            EatHandler forceEat =newEatHandler(ForceEat);

 

            happyEat(food);

            fattyEat(food);

            forceEat(food);

           

            Console.ReadLine();

        }

    }

}

 

2  使用委托的实现方式一

       对于静态方法,委托对象封装要调用的方法。

using System;

using System.Text;

 

namespace 场景一的模拟一

{

    publicdelegate voidEatHandler(string arg);

    classProgram

    {

        staticvoid HappyEat(string food)

        {

            Console.WriteLine("喜羊羊吃{0}",food);

        }

        staticvoid FattyEat(string food)

        {

            Console.WriteLine("懒羊羊吃{0}", food);

        }

        staticvoid ForceEat(string food)

        {

            Console.WriteLine("沸羊羊吃{0}", food);

        }

 

        staticvoid Main(string[] args)

        {

            stringfood ="grass";

//happyEat(food);

            //fattyEat(food);

            //forceEat(food);

 

            EatHandler happyEat =newEatHandler(HappyEat);

            EatHandler fattyEat =newEatHandler(FattyEat);

            EatHandler forceEat =newEatHandler(ForceEat);

 

            EatHandler eatHandlerChain = happyEat + fattyEat + forceEat;

            //一旦为委托分配了方法,委托将与该方法具有完全相同的行为。

           eatHandlerChain(food);

           

            Console.ReadLine();

        }

    }

}

 

3  使用委托的实现方式二

       对于实例方法,委托对象同时封装一个实例和该实例上的一个方法。

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace 场景一的模拟二

{

    classGoat

    {

        privatestring name;

 

        publicGoat(string name)

        {

            this.name= name;

        }

 

        publicvoid Eat(string food)

        {

            Console.WriteLine("{0} eat {1}.",name,food);

        }

    }

}

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace 场景一的模拟二

{

    publicdelegate voidEatHandler(string arg);

    classProgram

    {

        staticvoid Main(string[] args)

        {

            Goat happyGoat =newGoat("Happy");

            Goat fattyGoat =newGoat("Fatty");

            Goat forceGoat =newGoat("Force");

 

            EatHandler happyEat =newEatHandler(happyGoat.Eat);

            EatHandler fattyEat =newEatHandler(fattyGoat.Eat);

            EatHandler forceEat =newEatHandler(forceGoat.Eat);

 

            EatHandler eatHandlerChain = happyEat + fattyEat + forceEat;

           eatHandlerChain("grass");

 

            Console.ReadLine();

        }

    }

}

 

 

事件(event

事件是委托的一种特殊形式,在发生其他类或对象关注的事情时,类或对象可通过事件通知它们,事件对象处理通知过程。

我们通过场景二的模拟来讲解事件:

这就是我们的需求就是场景二,现在我们要求通过程序来演绎这个过程。

这里有两个问题需要解决:

问题一:程序需要几个类?

问题二:两个类之间有什么关系,或者说你如何来处理两个类之间的关系

我们先来看一下程序员小菜的的分析:

(一)小菜说,这个问题我们需要两个类:WolfGoat,当WolfShout方法触发时,Goat就执行Run方法。

这里小菜说得很对,但是关键的问题在于,我们如何让WolfShout方法触发时Goat就执行Run方法呢?写过程序的人都碰到过类似的问题,如当你单击一个按钮的时候,这时就自动执行一段代码,这两个问题是一样的。

(二)小菜说:这事简单,在主Main函数中先调用一下WolfShout方法,然后再调用GoatRun方法,这不就解决了。

这里小菜的思路演绎出来的故事是什么样的故事呢?故事应该是这样的:故事里一共有四个“人”物,灰太狼,喜羊羊,懒羊羊,还有一个就是你,当灰太狼来的时候,你在一边通知了喜羊羊和懒羊羊,然后懒羊羊才跑开。

我们要求的是当灰太狼的Shout方法执行时,自动执行GoatRun方法,这样才合乎现实的逻辑。

(三)小菜又说:那我可以在Wolf类中关联Goat类啊,直接在WolfShout方法中加入GoatRun方法不也可以实现吗?

这里的问题是什么呢?这就相当于灰太狼跑两只羊面前去,说:嗨,哥们,我是灰太狼,你们快跑。如果真是这样的话,所有的狼就都饿死了,不出多久,狼将成国家一级保护动物被圈养在动物园里了。

 

那我们究竟该如何来演绎这个故事呢?最好的方法就是用委托事件。

(一)  我们先来看两行代码:

public delegate voidWolfShoutEventHandler();

这里声明了一个委托,名称是WolfShoutEventHandler,我们说过,委托是对函数的一种封装,它实现了类似C++中函数指针的功能,这个委托所能代表的方法是无参数,无返回值的方法。

public event WolfShoutEventHandlerWolfShout();

这里声明了一个对外公开的public事件WolfShout,它的事件类型是委托WolfShoutEventHandler(委托是一种数据类型),表明事件发生时,执行被委托的方法。

 

(二)  我们来看类WolfGoat的设计

 

class Wolf

   {

       private string name;

       public Wolf(stringname)

       {

            this.name= name;

       }

 

       public delegate void WolfShoutEventHandler();

       public event WolfShoutEventHandler WolfShout;

 

       public voidShout()

       {

            Console.WriteLine("哈,我是{0}.",name);

 

            if(WolfShout != null)

            {

                WolfShout();

            }

       }

}

class Goat

   {

       private stringname;

       public Goat(stringname)

       {

            this.name= name;

       }

 

       publicvoid Run()

       {

            Console.WriteLine("灰太狼来了,{0}快跑",name);

       }

   }

 

 

class Program

   {

       static void Main(string[]args)

       {

            Wolf GreyWolf = new Wolf("Wolfy");

            Goat FattyGoat = new Goat("Fatty");

            Goat HappyGoat = new Goat("Happy");

 

            GreyWolf.WolfShout += newWolf.WolfShoutEventHandler(FattyGoat.Run);

            GreyWolf.WolfShout += newWolf.WolfShoutEventHandler(HappyGoat.Run);

 

            GreyWolf.Shout();

 

           Console.Read();

       }

   }

 

 

(三)  通过上面的内容,我们已经可以理解单击一个按钮自动执行一个代码的原理了,下面的例子可以让你知道sendere有什么用?

我们对上面的例子稍做改动,首先增加一个WolfShoutEventArgs,让它继承EventArgs,EventArgs是包含事件数据的类的基类,也就是说,这个类是用来在事件触发时传递数据用的。WolfShoutEventArgs类实际代码如下:

class WolfShoutEventArgs:EventArgs

   {

       private string name;

       public string Name

       {

            get{ return name; }

            set{ name = value; }

       }

}

 

class Wolf

   {

       private string name;

       public Wolf(stringname)

       {

           this.name= name;

       }

 

       public delegate void WolfShoutEventHandler(object sender,WolfShoutEventArgsargs);

       public event WolfShoutEventHandler WolfShout;

 

       public voidShout()

       {

            Console.WriteLine("哈,我是{0}.", name);

 

            if(WolfShout != null)

            {

                WolfShoutEventArgse =newWolfShoutEventArgs();

                e.Name = name;

                WolfShout(this, e);

            }

       }

   }

 

 

class Goat

   {

       private string name;

       public Goat(stringname)

       {

            this.name= name;

       }

 

       public void Run(object sender,WolfShoutEventArgsargs)

       {

//object sender 就是传送发送通知的对象

            Console.WriteLine("{0}来了,{1}快跑",args.Name,name);

       }

   }

 

class Program

   {

       static void Main(string[]args)

       {

            WolfGreyWolf = new Wolf("Wolfy");

            GoatFattyGoat = new Goat("Fatty");

            GoatHappyGoat = new Goat("Happy");

 

            GreyWolf.WolfShout += newWolf.WolfShoutEventHandler(FattyGoat.Run);

            GreyWolf.WolfShout += newWolf.WolfShoutEventHandler(HappyGoat.Run);

 

            GreyWolf.Shout();

 

            Console.Read();

       }

   }

上课时用的讲述委托与事件例子,望对大家有用,针对初学者,高手请略过。ppt与代码下载地址:http://download.csdn.net/detail/liusheng010/5854453

原创粉丝点击