委托和事件

Posted

tags:

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

1.委托:想把一个方法做为参数进行传递,委托就是指向一个方法

2、参考 http://www.tracefact.net/CSharp-Programming/Delegates-and-Events-in-CSharp.aspx
学习委托和事件

3、声明一个委托,指向一个方法
public delegate void GreetingDelegate(string name);
public void GreetPeople(string name, GreetingDelegate MakeGreeting){
MakeGreeting(name);
}

委托的声明方式和类却完全不同,这是怎么一回事?实际上,委托在编译的时候确实会编译成类。因
为Delegate是一个类,所以在任何可以声明类的地方都可以声明委托。

 

4、委托不同于string的一个特性:

可以将多个方法赋给同一个委托,或者叫将多个方法绑定 到同一个委托,当调用这个委托的时候,将依次调用其所绑定的方法
使用委托可以将多个方法绑定到同一个委托变量,当调用此变量时(这里用“调用”这个词,是因为 
此变量代表一个方法),可以依次调用所有绑定的方法。

我们继续思考上面的程序:实际 应用中,通常都是 GreetPeople 在一个类中,ChineseGreeting和 EnglishGreeting 在另外的类中 
。现在你已经对委托有了初步了解,是时候对上面的例子做个改进了。假设我们将GreetingPeople() 
放在一个叫GreetingManager的类中,那么新程序应该是这个样子的:

技术分享
 1  public class GreetManager
 2     {
 3         public event GreetingDelegate MakingGreet;
 4         public void GreetPeople(string name)
 5         {
 6             MakingGreet(name);
 7         }
 8     }
 9 
10     public delegate void GreetingDelegate(string name);
11     public partial class Form1 : Form
12     {
13         public Form1()
14         {
15             InitializeComponent();
16         }
17 
18         private void EngishGeeting(string name)
19         {
20             MessageBox.Show(name);
21         }
22         private void ChineseGeeting(string name)
23         {
24             MessageBox.Show(name);
25         }      
26 
27         private void button1_Click(object sender, EventArgs e)
28         {
29             GreetManager gm = new GreetManager();
30             gm.MakingGreet += ChineseGeeting;
31             gm.GreetPeople("你好");
32         }   
33     }
View Code

 

5、封装属性

如果delegate1不是一个委托类型,而是一个string类型,你会怎么做?答案是使用属性对字段进行封装。

于是,Event出场了,它封装了委托类型的变量,使得:在类的内部,不管你声明它是public还是
protected,它总是private的。在类的外部,注册“+=”和注销“-=”的访问限定符与你在声明事件
时使用的访问符相同。

技术分享
1   public class GreetManager
2    {
3      public event GreetingDelegate MakingGreet;
4      public void GreetPeople(string name)
5      {
6         MakingGreet(name);
7      }
8   }
View Code

 

 6、事件 

很容易注意到:MakeGreet 事件的声明与之前委托变量delegate1的声明唯一的区别是多了一个event
关键字。看到这里,在结合上面的讲解,你应该明白到:事件其实没什么不好理解的,声明一个事件
不过类似于声明一个进行了封装的委托类型的变量而已。

技术分享
1   private void button1_Click(object sender, EventArgs e)
2         {
3             GreetManager gm = new GreetManager();
4             gm.MakingGreet += ChineseGeeting;
5             gm.GreetPeople("你好");
6         }
View Code

 

  7、Observer设计模式

为了定义对象间的一种一对多的依赖关系,以便于当一个对象的状态改变时,其
他依赖于它的对象会被自动告知并更新。Observer模式是一种松耦合的设计模式。

技术分享
 1  public partial class Form1 : Form
 2     {
 3         public Form1()
 4         {
 5             InitializeComponent();
 6         }
 7 
 8         private void button1_Click(object sender, EventArgs e)
 9         {
10             Heater heater = new Heater();
11             Alerm mAlert = new Alerm();
12             heater.boilEvent += mAlert.MakeAlert;
13             heater.boilEvent += Display.ShowMessage;
14             heater.BoilWater();
15         }
16     }
17 
18     public class Heater
19     {
20         private int tempeter;
21         public delegate void BoilHandler(int parm);
22         public event BoilHandler boilEvent;
23         public void BoilWater()
24         { 
25           for(int i=0;i<=100;i++)
26           {
27               tempeter = i;
28               if(tempeter>95)
29               {
30                   //如果对象有注册
31                   if(boilEvent!=null)
32                   {
33                       boilEvent(tempeter);
34                   }
35               }
36           }            
37         }
38     }
39 
40     public class Alerm
41     {
42         public void MakeAlert(int param)
43         {
44             string message = "Alerm:水已经{0}度了"+ param;
45             MessageBox.Show(message);
46         }
47     }
48 
49     public class Display
50     {
51         public static void ShowMessage(int param)
52         {
53             string message = "Display:当前温度:{0}" + param;
54             MessageBox.Show(message);
55         }
56     }
57   
View Code

 

8、 .Net Framework的编码规范:

委托类型的名称都应该以EventHandler结束。
委托的原型定义:有一个void返回值,并接受两个输入参数:一个Object 类型,一个 EventArgs类
型(或继承自EventArgs)。
事件的命名为 委托去掉 EventHandler之后剩余的部分。
继承自EventArgs的类型应该以EventArgs结尾。
再做一下说明:

委托声明原型中的Object类型的参数代表了Subject,也就是监视对象,在本例中是 Heater(热水器)
。回调函数(比如Alarm的MakeAlert)可以通过它访问触发事件的对象(Heater)。
EventArgs 对象包含了Observer所感兴趣的数据,在本例中是temperature。

技术分享
 public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Heater heater = new Heater();
            Alerm mAlert = new Alerm();
            heater.Boiled += mAlert.MakeAlert;
            heater.Boiled += Display.ShowMsg;
            heater.BoilWater();
        }

    }

    public class Heater
    {
        private int tempeter;
        public string type = "001";
        public string are = "china guangzhou";
        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 temp)
            {
                this.temperature = temp;
            }

        }

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

        }
    }

    public class Alerm
    {
        public void MakeAlert(object sender,Heater.BoiledEventArgs e)
        {
            Heater heater = (Heater)sender;
            string message = "Alerm:水已经{0}度了"+e.temperature+"_" + heater.are+ "_"+heater.type;
            MessageBox.Show(message);
        }
    }

    public static class Display
    {
        public static void ShowMsg(object sender, Heater.BoiledEventArgs e)
        {
            Heater heater = (Heater)sender;
            string message = "Display:温度为" + e.temperature + "_" + heater.are + "_" + heater.type;
            MessageBox.Show(message);
        }
    }
View Code

 

























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

原生js如何绑定a连接点击事件?

编写高质量代码改善C#程序的157个建议——建议137:委托和事件类型应添加上级后缀

jQuery事件绑定和委托实例

C#事件

概念篇-委托和事件

C#系列你应该知道的委托和事件