委托与事件

Posted 唐世光

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了委托与事件相关的知识,希望对你有一定的参考价值。

明天还要上班,可我这会儿,总想着写篇博文,要不感觉就像丢了件东西似的,睡不着。成全我自己吧。

刚走入工作的我,为了更好的工作,我就让自己回炉一次,更深入的理解各个知识点。

今晚就从委托与事件开始。。

 

1.什么是委托。

 

委托是一种数据结构,能够引用静态方法或引用实例及其实例方法,他是完全面向对象的,同时也封装了对象实例和方法。委托实例封

装了一个调用列表,该列表包含了一个会多个方法,每个方法称为一个可调用实体。

 

2.我用代码展示委托使用的全过程。(看从1-->5的顺序)

 

 

技术分享
    //1.委托的声明,delegate为声明委托的关键字;
    //public为修饰符,还可以有的修饰符为 protected、internal、private、new
    //new修饰符,只能在其他类型中声明委托时使用,他表示所标明的委托会隐藏具有相同名称的继承成员
   public delegate void D(int i, int j);
   public  class Program
    {
        static void Main(string[] args)
        {
            //3.委托实例化可以创建委托类型的实例,并向该实例注册方法列表
            //委托类型的实例方法列表可以为静态方法,实例方法,或者另外一个委托实例。
            D d1 = new D(U.F1);
            D d2 = new D(U.F2);
            D d3 = d1 + d2;        //这样表示d3实例依次调用U类的F1、F2方法
            D d4 = d3 - d1;       //表示从d3实例的方法列表末端查找,如果该方法包括d1,则移除

            //5.委托的调用
          d1(200, 100);   //输出为300
          d2(200, 100);   //100
          d3(50, 10);     //60 40  这里由于实例方法列表中有2个方法,也就调用执行了2个方法,故导出2个值
          d4(70, 40);     // 30
          Console.ReadKey();
        }        
    }
   public class U
    {
        //2.创建向委托注册的方法
        //如果一个方法能够注册到某一个委托中,那么该方法的签名必须与该委托所指定的签名完全匹配
        //匹配规则有2:返回类型必须相同;方法参数必须相同。

        public static void F1(int a, int b)
        {
            
            Console.WriteLine((a+b).ToString());
        }
        public static void F2(int w, int j)
        {
            Console.WriteLine((w-j).ToString());
        }
    }
技术分享

 

3. 委托的你深入应用

 

技术分享
 public delegate void helloWorld(string name);  //声明委托
    class Program
    {
        static void Main(string[] args)
        {
           //最初的委托
            helloWorld ffdelegate = new Program().ff;  //这里可以直接写入方法。
            ffdelegate("最初最简单的,");

            //使用匿名方法。。
            helloWorld sedelegate = delegate(string name) { Console.WriteLine(name+",你好!"); };
            sedelegate("匿名方法");           

            //使用拉姆达表达式
            helloWorld thdelegate = (p => { Console.WriteLine(p+",你好"); });
            thdelegate("拉姆达表达式");

            //使用Action
            Action<string> fordelegate=(p=>{Console.WriteLine(p+",你好!");});
            fordelegate("Action");

            //使用Func
            Func<string, string> fidelegate = (p => p + ",你好!");
            string sayHello = fidelegate("Func");
            Console.WriteLine(sayHello);

            Console.ReadKey();

        }

        public void ff(string name)
        {
            Console.WriteLine(name+"你好!");
        }
    }
技术分享

 

4.事件的使用

 

事件是一种使对象或类能够提供通知的成员,其实也是一种特殊类型的委托。他包含两个参数:指示事件源的“对象源”参数和封装事件的其他任何相关信息的e参数。其中,e参数的类型为system.EventArgs类型或从这类型中派生的类型。

 

 1.事件的简单认识

 

 

技术分享
namespace 事件
{
    public delegate void GreetingDelegate(string name); //声明委托
    class Program
    {
        private static void ChineseGreeting(string name)  //定义事件处理程序
        {
            Console.WriteLine("你好, " + name);
        }

        static void Main(string[] args)
        {
            GreetingManager gm = new GreetingManager();
            gm.MakeGreet += ChineseGreeting;        //订阅事件(将事件处理程序添加到事件的调用列表中)
            gm.GreetPeople("事件!");
            Console.ReadKey();
        }
    }
    public class GreetingManager
    {

        public event GreetingDelegate MakeGreet;  //声明一个事件,event为声明事件的关键字,其实事件是一种特殊类型的委托
        public void GreetPeople(string name)
        {
            MakeGreet(name);                 //把这里的事件看做一个委托来理解,更容易点。
        }
    }
}
技术分享

 

2.事件的应用 (Observer设计模式--热水器)

 

技术分享
using System;
using System.Collections.Generic;
using System.Text;

namespace Delegate {
    // 热水器
    public class Heater {
       private int temperature;
       public string type = "RealFire 001";       // 添加型号作为演示
       public string area = "China Xian";         // 添加产地作为演示
       //声明委托
       public delegate void BoiledEventHandler(Object sender, BoiledEventArgs e);
       public event BoiledEventHandler Boiled; //声明事件

       // 定义BoiledEventArgs类,传递给Observer所感兴趣的信息
       public class BoiledEventArgs : EventArgs {
           public readonly int temperature;
           public BoiledEventArgs(int temperature) {
              this.temperature = temperature;
           }
       }

       // 可以供继承自 Heater 的类重写,以便继承类拒绝其他对象对它的监视
       protected virtual void OnBoiled(BoiledEventArgs e) {
           if (Boiled != null) { // 如果有对象注册
              Boiled(this, e);  // 调用所有注册对象的方法
           }
       }
       
       // 烧水。
       public void BoilWater() {
           for (int i = 0; i <= 100; i++) {
              temperature = i;
              if (temperature > 95) {
                  //建立BoiledEventArgs 对象。
                  BoiledEventArgs e = new BoiledEventArgs(temperature);
                  OnBoiled(e);  // 调用 OnBolied方法
              }
           }
       }
    }

    // 警报器
    public class Alarm {
       public void MakeAlert(Object sender, Heater.BoiledEventArgs e) {
           Heater heater = (Heater)sender;     //这里是不是很熟悉呢?
           //访问 sender 中的公共字段
           Console.WriteLine("Alarm:{0} - {1}: ", heater.area, heater.type);
           Console.WriteLine("Alarm: 嘀嘀嘀,水已经 {0} 度了:", e.temperature);
           Console.WriteLine();
       }
    }

    // 显示器
    public class Display {
       public static void ShowMsg(Object sender, Heater.BoiledEventArgs e) {   //静态方法
           Heater heater = (Heater)sender;
           Console.WriteLine("Display:{0} - {1}: ", heater.area, heater.type);
           Console.WriteLine("Display:水快烧开了,当前温度:{0}度。", e.temperature);
           Console.WriteLine();
       }
    }

    class Program {
       static void Main() {
           Heater heater = new Heater();
           Alarm alarm = new Alarm();

           heater.Boiled += alarm.MakeAlert;   //注册方法
           heater.Boiled += (new Alarm()).MakeAlert;      //给匿名对象注册方法
           heater.Boiled += new Heater.BoiledEventHandler(alarm.MakeAlert);    //也可以这么注册
           heater.Boiled += Display.ShowMsg;       //注册静态方法

           heater.BoilWater();   //烧水,会自动调用注册过对象的方法
       }
    }
}

输出为:
Alarm:China Xian - RealFire 001:
Alarm: 嘀嘀嘀,水已经 96 度了:
Alarm:China Xian - RealFire 001:
Alarm: 嘀嘀嘀,水已经 96 度了:
Alarm:China Xian - RealFire 001:
Alarm: 嘀嘀嘀,水已经 96 度了:
Display:China Xian - RealFire 001:
Display:水快烧开了,当前温度:96度。
// 省略 ...

以上是关于委托与事件的主要内容,如果未能解决你的问题,请参考以下文章

事件与委托

C#编程之委托与事件四

直接事件与事件委托

理解Javascript中的事件绑定与事件委托

冒泡事件与事件委托

C# 再次理解委托事件与函数作为参数