实例分析:事件与委托

/*事件*/
    public delegate void TimeEventHandler(string s);//委托声明
    class MyTime
    {
        public event TimeEventHandler Timer;//声明事件
        public void OnTimer(string s)
        {
            if (null != Timer)
            {
                Timer(s);//引发事件
            }
        }
    }

    class ProcessTime
    {
        //事件处理
        public void GenerateTime(string s)
        {
            Console.WriteLine("Hello {0}! The time is {1} now", s, DateTime.Now);
        }
    }
    class TestTime
    {
        public static void Main()
        {
            ProcessTime p = new ProcessTime();
            MyTime t = new MyTime();
            t.Timer+=new TimeEventHandler(p.GenerateTime);//把事件与事件处理联系起来
            t.OnTimer("Peter");//引发事件
            Console.Read();
        }
    }

 


    /*委托*/
    delegate void TimeDelegate(string s);//委托声明
    class MyTime
    {
        public static void HelloTime(string s)
        {
            Console.WriteLine("Hello {0}! The time is {1} now", s, DateTime.Now);
        }

        public static void GoodbyeTime(string s)
        {
            Console.WriteLine("Goodbye {0}! The time is {1} now", s, DateTime.Now);
        }

        public void SayTime(string s)
        {
            Console.WriteLine("{0}! The time is {1} now", s, DateTime.Now);
        }
    }

    class TestDelegate
    {
        public static void Main()
        {
            //委托实例化,创建委托实例a,并封装静态方法HelloTime
            TimeDelegate a = new TimeDelegate(MyTime.HelloTime);
            Console.WriteLine("Invoking delegate a:");
            //委托调用,相当于调用方法MyTime.Hello("A")
            a("A");
            TimeDelegate b = new TimeDelegate(MyTime.GoodbyeTime);
            Console.WriteLine("Invoking delegate b:");
            b("B");
            //委托实例c封装了两个方法HelloTime和GoodbyeTime
            TimeDelegate c = a + b;
            Console.WriteLine("Invoking delegate c:");
            c("C");
            c -= a;
            Console.WriteLine("Invoking delegate c:");
            c("C");
            MyTime t = new MyTime();
            TimeDelegate d = new TimeDelegate(t.SayTime);
            Console.WriteLine("Invoking delegate d:");
            d("D");
            Console.Read();
        }
    }


一、委托
委托类似于函数指针,但函数指针只能引用静态方法,而委托既能引用静态方法,也能引用实例方法。

委托使用分三步:1、委托声明。2、委托实例化。3、委托调用。
例程一:
using System;

namespace 委托
{
  delegate int NumOpe(int a,int b); //委托声明
  class Class1
  {
    static void Main(string[] args)
    {
      Class1 c1 = new Class1();
      NumOpe p1 = new NumOpe(c1.Add); //委托实例化
      Console.WriteLine(p1(1,2)); //委托调用
      Console.ReadLine();
    }

    private int Add(int num1,int num2)
    {
      return(num1+num2);
    }
  }
}
例中,委托NumOpe引用了方法Add。
委托声明了以后,就可以象类一样进行实例化,实例化时把要引用的方法(如:Add)做为参数,这样

委托和方法就关联了起来,就可以用委托来引用方法了。
委托和所引用的方法必须保持一致:
1、参数个数、类型、顺序必须完全一致。
2、返回值必须一致。

二、事件

事件有很多,比如说鼠标的事件:MouserMove,MouserDown等,键盘的事件:KeyUp,KeyDown,KeyPress

有事件,就会有对事件进行处理的方法,而事件和处理方法之间是怎么联系起来的呢?委托就是他们中

间的桥梁,事件发生时,委托会知道,然后将事件传递给处理方法,处理方法进行相应处理。

比如在WinForm中最常见的是按钮的Click事件,它是这样委托的:this.button1.Click += new

System.EventHandler(this.button1_Click);按按钮后就会出发button1_Click方法进行处理。

EventHandler就是系统类库里已经声明的一个委托。

三、自定义事件及其处理

EventHandler以及其它自定义的事件委托都是一类特殊的委托,他们有相同的形式:

delegate void 事件委托名(object sender,EventArgs e);

object用来传递事件的发生者,比如二中的Button控件就是一个事件发生者;EventArgs用来传递事件

的细节。

例程二:
using System;

namespace 最简单的自定义事件
{
  /// <summary>
  /// 事件发送类
  /// </summary>
  class Class1
  {
    public delegate void UserRequest(object sender,EventArgs e); //定义委托
    public event UserRequest OnUserRequest; //定义一个委托类型的事件

    public void run()
    {
      while(true)
      {
        if(Console.ReadLine()=="a")
        {//事件监听
          OnUserRequest(this,new EventArgs()); //产生事件
        }
      }
    }
  }

  /// <summary>
  /// 事件接收类
  /// </summary>
  class Class2
  {
    static void Main(string[] args)
    {
      Class1 c1 = new Class1();
      c1.OnUserRequest += new Class1.UserRequest(c1_OnUserRequest); //委托实例化后绑定到事


      c1.run();
    }

    private static void c1_OnUserRequest(object sender, EventArgs e)
    {//事件处理方法
      Console.WriteLine("/t你触发了事件!");
    }
  }
}
例程三:
using System;

namespace 带事件数据的事件
{
  /// <summary>
  /// 带事件数据的事件类,从EventArgs继承
  /// </summary>
  class OnUserRequestEventArgs:EventArgs
  {
    private string inputText;
    public string InputText
    {
      get
      {
        return inputText;
      }
      set
      {
        inputText = value;
      }
    }
  }

  /// <summary>
  /// 事件发送类
  /// </summary>
  class Class1
  {
    public delegate void UserRequest(object sender,OnUserRequestEventArgs e);
    public event UserRequest OnUserRequest;

    public void run()
    {
      while(true)
      {
        Console.WriteLine("请输入内容:");
        string a=Console.ReadLine();
        //if(a=="a")
        //{
        OnUserRequestEventArgs e1 = new OnUserRequestEventArgs();
        e1.InputText = a;
        OnUserRequest(this,e1);
        //}
      }
    }
  }

  /// <summary>
  /// 事件接收类
  /// </summary>
  class Class2
  {
    [STAThread]
    static void Main(string[] args)
    {
      Class1 c1 = new Class1();
      c1.OnUserRequest += new Class1.UserRequest(c1_OnUserRequest);
      c1.run();
    }

    private static void c1_OnUserRequest(object sender, OnUserRequestEventArgs e)
    {
      Console.WriteLine("/t你输入的是:"+e.InputText);
    }
  }
}
例程三跟例程二唯一的差别在于自定义了一个类OnUserRequestEventArgs,从EventArgs继承。

 


女儿想吃棒冰了,但又不想自己顶着太阳出去买(买棒冰是一个method),所以她叫他倒霉的老爸去买

(delegate),最后女儿吃到了棒冰。
这就是一个委托的过程。
接下去,让我们看看一些对委托的解释:

委托是用来处理其他语言(如 C++、Pascal 和 Modula)需用函数指针来处理的情况的。不过与 C++

函数指针不同,委托是完全面对对象的;另外,C++ 指针仅指向成员函数,而委托同时封装了对象实例

和方法。

委托实例的一个有趣且有用的属性是:它不知道也不关心它所封装的方法所属的类;它所关心的仅限于

这些方法必须与委托的类型兼容(第 15.1 节)。这使委托非常适合于“匿名”调用。——《C#语言规

范》Scott Wiltamuth 和 Anders Hejlsberg

这些解释看起来都是比较艰涩难懂的,让我们用一个例子来充分理解一个简单的委托吧。

首先,建立一个Father类,拥有2个Shared方法(C#为static,即静态方法):
OpenTV
BuyToys
天下的所有父亲都有帮女儿开电视和买玩具的义务,哈哈
Public Class Father

    Public Shared Sub OpenTV(ByVal msg As String)
        Console.WriteLine("Mission:" & msg)
        Console.WriteLine("Mission is completed!")
    End Sub

    Public Shared Sub BuyToys(ByVal msg As String)
        Console.WriteLine("Mission:" & msg)
        Console.WriteLine("Mission is completed!")
    End Sub

End Class

值得注意的是,这2个方法都有一个string的参数,等会儿定义委托的时候也需要相似的参数,这个后

面再讲。

然后我们要创建委托。需要注意的是,委托是个类,我们要和对待其他类一样对待他,创建委托需要2

道手续:
1,定义一个Delegate类,这个类应当与你想要传递的方法具有相同的参数和返回值类型。
对应上面的说明,我们创建的类如下:
Public Delegate Sub DelegatebyFather(ByVal msg As String)

c#代码:
public Delegate void DelegatebyFather(String msg);

2,生成一个delegate对象,并将你想要传递的方法作为参数传入(就是把你想让这个委托做的事情传

递进取)。
对应上门的说明,我们创建的对象如下:
Dim mydelegate As DelegatebyFather
        mydelegate = New DelegatebyFather(AddressOf Father.BuyToys)
c#代码:
DelegatebyFather mydelegate;
mydelegate=new DelegatebyFather(Father.BuyToys);


这2行代码我们可以理解成:女儿和老爸签订了一个委托协议(XX条约?),协议的内容是,老爸去做

BuyToys这件事情。

然后,女儿就可以通过mydelegate这个委托的对象(XX条约),来给老爸发号施令了,代码如下:
mydelegate.Invoke("buy many toys!")
老爸去买玩具吧!

这里我们显式调用了Delegate类的Invoke方法,我们也可以隐式调用:
mydelegate("buy many toys!")

隐式调用看上去就像是一个函数,其实,编译器会在IL代码中自动加上Invoke的。
至于c#,只能使用隐式调用,用显式会报错,c#代码如下:
mydelegate("buy many toys!")


这样,一个简单的委托过程就结束了,让我们贴一下完整的主程序吧:
Module Module1

    Sub Main()
        Dim mydelegate As DelegatebyFather
        mydelegate = New DelegatebyFather(AddressOf Father.BuyToys)

        mydelegate.Invoke("buy many toys!")
    End Sub


    Public Delegate Sub DelegatebyFather(ByVal msg As String)

End Module

执行的结果如下:
Mission:buy many toys!
Mission is completed!

 

 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值