理解C#中的代理和事件

解C#中的代理和事件(一)

  突然写这篇文章,真的有点,是在做作的感觉,我想这并不是什么,难以

理解的东西,事实上,很多人都写过,而且,我保证至少不比我写的差.可是

还是觉得有必要提出来.因为要去正确的理解代理和事件是很有趣的,也是

很必要的.那么好吧,下面我就来讲讲,它们之间的关系.当然还会有些例子.

  首先我想说说有关事件.事件顾名思义当然是windows程序收到的消息.

那么我举几个有关事件的例子,如鼠标移动.按下.之类的都是.那么代理呢?

很多人都说它看上去,就是想是一个受托管的函数指针.我觉得这种说法很

正确,事实如此.在MSDN上,我们经常可以看到,有关代理的"多路广播"这个词

我觉得不错,可是不好理解.但我会在下面详细讲解的.

代理:(有的书上也翻译成指代或委托.英文是这样一来的"Delegate")

我想很多刚接触C#的人,都会对代理产生兴趣的.事实上也是如此,不了解它,你就没办法

来做windows程序.和传统意义上的函数指针有所不同的是,代理在C#中是一种类型,这样

它看上去,更安全也,更符合OO精神.代理实际上所做的工作就是通过引用把函数包裹起来

并使函数有一个有效的返回值.不知道我这样说是否好理解.那么我举个例子,你去建造房子.

很显然,我是在说你所做的事情.那么建造房子就是代理,它指代了,你要做的事情,可是它并

没有去做任何事情,事实上是,在建造房子这个工作里,你做了,那么结果是什么?当然是建立

一座房子.是的,建造房子就是代理,而如何建造房子则是函数应该完成的工作.而建造的是什么样

的房子,则是返回值.还记得,我曾经说过,代理是一种类型吗?呵呵..我想你应该记得,因为,

那是很新颖的,至少当时我那么认为.好吧,让我们来看看名称空间System.Delagate,看见了吗?那

就代理类.

举个例子: public delegate void GetString()//我申明了一个代理

现在我要用到它了如下; int i=100; GetString gs=new GetString(i.ToString);//这里我吧int的ToString方法

填入了一个代理中.看上去想构造函数.这就是常在书上看到的"名称等效的,而

不是结构等效的",我想看到这儿你还是不明白.那么,我再来一个代理

如下:

float j=0.0001;

GetString gs=new GetString(j.ToString);//瞧见了,int的ToString方法

和float的ToString方法的结构是不一样的,可是名称和类型的返回值和

参数都一样.现在,我想,你应该理解了吧.

可是,我们经常会在MSDN中看到,这样的句子.单路代理和多路广播.看上去,有点不好理解.

事实上,我开始看这样的句子,是有点头痛的.那么,我想例子是最好的解说方式.

Single Delegate:(单路代理)

从字面上,我们可以这样来理解,这个代理只是单单代理了一个函数的工作.那么好吧,让

我们来看看它是如何工作的.下面我就来定义一个这样的代理:

public delegate bool Myfun(string str,int i)

现在我再来写一个方法如下:   bool CompareStrToInt(string s,int i) {    if(s.CompareTo(i.ToString())==0)         return true;     else          return false; }

这个方法完成的工作很简单对吧,只是比较字符而已.那么和代理有什么关系呢?还记得

我说的话吗?代理就是在把动词名词化.代码如下:

Myfun mf=new  (CompareStrToInt);

string s="10000"; int i=10000; ConSole.WriteLine("Value="+mf(s,i));

输出结果:

Value=true

这就是单路代理.它只代理一个.好吧,也许你想看看复杂的例子,更有趣的在后面呢,

该是讨论多路广播的时候了.

多路广播:

一个代理同时代理几个方法.就是我们前面说到的那样,你去建造房子,现在要不仅仅是

建造住宅,还的去建造花园等等其它建筑物.可是它们都是在建造房子,传递的参数也相同

返回值的类型也相同都是房屋.那么我们为什么不找一个代理人来完成这样的任务呢?把

这些事物交由他一个人来完成不是可以节省我们很多的时间和金钱.是的我们可以那样做

System.MulticastDelegate 实际上在.net framework中你还可以找到这个类,多路代理

MSDN上翻译成多路广播.事实上它还重载了操作符+=.其实多路广播和单路代理在使用方法

上区别不大.你可以看下面的例子.

using System;

namespace Multi_castDelegate {   /// <summary>   /// Summary description for Class1.   /// </summary>   class MyClassDelegate   {     /// <summary>     /// The main entry point for the application.     /// </summary>         public delegate string IntDelegate(string s);   } } using System;

namespace Multi_castDelegate {   /// <summary>   /// Summary description for MyImplementingClass.   /// </summary>   public class MyClass   {     public MyClass()     {           }

    public static string WriteString(string s)     {       Console.WriteLine("Writing string");       return "null";     }

    public static string logString(string s)     {       Console.WriteLine("loging string");        return "null";     }

    public static string TransmitString(string s)     {       Console.WriteLine("Transmitting string");        return "null";            }   } }

The Main class: using System; using System.Threading; namespace Multi_castDelegate {   /// <summary>   /// Summary description for Test.   /// </summary>   public class Test   {     public static void Main()     {       MyClassDelegate.StringDelegate         Writer,Logger,Transmitter;

      MyClassDelegate.StringDelegate         myDelegate;

      Writer=new                    MyClassDelegate.StringDelegate(MyClass.WriteString);       /// calling Writer       Writer("hello i am Writer just acting like Single cast");       Logger=new MyClassDelegate.StringDelegate(MyClass.logString);       ///calling Logger       Logger("hello i am Logger just acting like Single-cast");       Transmitter=new MyClassDelegate.StringDelegate(MyClass.TransmitString);       ///calling Transmitter             Transmitter("hello i am Transmitter just acting like Single-cast");        ///here mydelegate used the Combine method of System.MulticastDelegate       ///and the delegates combine         myDelegate=(MyClassDelegate.StringDelegate)System.Delegate.Combine(Writer,Logger);              myDelegate("used Combine");       ///here Transmitter is also added using the overloaded form of Combine       myDelegate+=Transmitter;       myDelegate("Using Overloaded Form");       ///now using the Remove method       myDelegate=(MyClassDelegate.StringDelegate)System.Delegate.Remove(myDelegate,Writer);             myDelegate("Without Writer");           ///overloaded Remove       myDelegate-=Transmitter;       myDelegate("Without Transmitter");         System.Threading.Thread.Sleep(2300);                   }   } }

(上面的例子是在一个国外网站上找到的,觉得不错,就直接套用了.)

上面的例子重点是看那两个已经重载的操作符."-="和"+=".通过上面的例子,你可以清楚的

看到多路广播是如何一次代理多个方法的.当然你也可以删除掉那些你不想要的用"-="操作

符就可以了.(那么我将在下一篇讨论事件)

 

嗨!大家好,还记得刚才的那篇关于代理的吗?你是不是要问我为什么要分开来写?

原因很简单他们说要7篇以上才可以成为专题作家.噢,天啊,事实上这是我的第九篇

可是那两篇.还在审核中.开玩笑的,事实上是,结构,代理和事件有联系,可是也是可以

分开来讨论的两个话题.这就是我为什么要分开,因为,很多朋友一开始用到代理和事件

的时候,都是在给一个button或一个窗体添加事件的时候用到的.所以经常可以看到,有

人一提到代理和事件就会自然想到windows的时间驱动.是的那是最常用的,可是事实上

也是可以分开使用的,至少代理就是那样的.代理可以脱离事件来独立生存.上面的那一篇

正如你看到的那样.好吧,不多说了,让我们进入正题.

事件:

理解事件,这一点也不难,事实上,每个人每天都在经历着这样或那样的事件,然后组成了,你

的生活.想想,一个天气预报员通知你说明天要下雨了.很自然的,你会想到,你该代把伞.是的

这就是事件.天气预报发出这个事件通知,然后你来处理这个事件.你所做的就是带把伞来挡雨.

就象你常做的那样,你点击一个button然后发出click事件,接下来当然是处理这个事件了,也许是

弹出一个窗口,或别的什么事情这些都有可能发生,甚至是关闭计算机.这些都是用户事件.因为用户

触发GUI然后发生这些事件.

下面我们来看看C#中是如何处理的.那么我前面的那篇中曾提到过,把动词变成名词.你会想到什么?

是+ing吗?哈哈..开个玩笑,当然不是,我们不是在做英文联系.好吧,是代理,就象你常做的那样

在IDE环境中,你拖一个button到窗体上,然后双击它,你会看到什么?进入代码界面了吗?然后你就

来处理事件.可这和代理有什么关系?恩,你为什么不仔细找找看通常有怎么

this.button1.Click += new System.EventHandler(this.button1_Click);一句在你的 InitializeComponent()函数中.是的,这就是代理.它把事件放入了代理中.那么事件呢?

在this.button1_Click方法中你会看到它有两个参数,一个是object类型的sender,这个很简单

顾名思义它就是事件的发起人.它是谁,你只要问问它就知道了.那么第二个呢?是事件,对吗?

当然,发起人带着他的事件来了,就象天气预报员带着他的天气预报来了一样.好了,相信我

人类总有一天可以制造天气.听着一定要相信我,出了打雷下雨等这些上帝已经预定好的天气

我们总有一天会创造出新的天气效果例如,下钱怎么样?呵呵..听上去是个不错的想法,虽然是

个玩笑.好的,你会说我准是疯了,干嘛说这些?不,我要谈到一个新的话题.那就是用户自定义

事件和系统预定义事件.那么下面我们来分别讨论这两种事件.

用户自定义事件:

我相信代码永远都是最有说服力的.就象你不愿意去看教材而更愿意去看科教电影那样.

下面的代码,就是我要说明的事实.

 

using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data;

namespace userEvent {  /// <summary>  /// Form1 的摘要说明。  /// </summary>  public delegate void MYShow();

 public class Form1 : System.Windows.Forms.Form  {   /// <summary>   /// 必需的设计器变量。   /// </summary>   private System.ComponentModel.Container components = null;         public event MYShow ShowME;   public Form1()   {    //    // Windows 窗体设计器支持所必需的    //    InitializeComponent();

   //    // TODO: 在 InitializeComponent 调用后添加任何构造函数代码    //                     this.ShowME();   }

  /// <summary>   /// 清理所有正在使用的资源。   /// </summary>   protected override void Dispose( bool disposing )   {    if( disposing )    {     if (components != null)     {      components.Dispose();     }    }    base.Dispose( disposing );   }

  #region Windows Form Designer generated code   /// <summary>   /// 设计器支持所需的方法 - 不要使用代码编辑器修改   /// 此方法的内容。   /// </summary>   private void InitializeComponent()   {    //    // Form1    //    this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);    this.ClientSize = new System.Drawing.Size(292, 273);    this.Name = "Form1";    this.Text = "Form1";             this.ShowME+=new MYShow(this.ShowMeName);       }   #endregion

  /// <summary>   /// 应用程序的主入口点。   /// </summary>   [STAThread]   static void Main()   {    Application.Run(new Form1());   }   void ShowMeName()   {    MessageBox.Show("I'm yarshray");   }  } }

看见上面的代码了吗?不用我多说,你也猜到我要说的是什么,看我自定义的一个代理

public delegate void MYShow(); 这个代理将要代理一个事件,它是在这儿定义的

如下:public event MYShow ShowME;我定义的这个事件的名字叫做ShowME是的,人如其名

就是要展示一下我,呵呵..,看看吧,下面的一句this.ShowME+=new MYShow(this.ShowMeName);

我使用了这个事件并把ShowMeName交给了他.这个方法很简单就是弹出一个对话框.写上我

的名字"yarshray",可是这这个事件是在那儿触发的呢?为什么不向上看?看见构造函数了吗?

是的,里面有一句 this.ShowME();,可是你知道,这样做没有任何意义,实际情况是需要自定义

消息然后把它掉到消息循环中,然后通过消息来触发事件.不过我只是在讲有关代理和事件,所以

并没有那么做.只为了图简便.让你能够看的更清楚.好了,用户自定义事件我就讲到这里.下面的

时间让我们来讲讲预定义事件.

 

预定义事件:

实际上不用我多说,大家都用到过.讲象我一开始说到的那样,天气预报员带着他的天气预报一样

那都是上帝预先安排好的那样,刮风下雨,下雪,冰雹等等.直接拿来使用就好了.就想一个按纽那样

点击.鼠标进入,鼠标移开,等等.例子我就不给了,谁都用过,

好了,我写完了,希望对你有点帮助,当然看上去,更象一堆废话,是吗?那好吧,你就当成是一种

消遣.最后还是谢谢各位能够看完.我还会写的.就这样,下回见.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值