现在的位置: 首页 > 综合 > 正文

委托 与 事件

2014年01月10日 ⁄ 综合 ⁄ 共 5448字 ⁄ 字号 评论关闭

   玩 C# 也快 3 个月了   对委托 事件  做个小总结     互相交流下   如果你是高手(就不用看了,很菜,如果你愿意指导下小弟,感激不尽!)

   废话少说   (花了我 3个小时 大哭+1) 

    1、

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace 委托
{
    class ABCD
    {
        //... A 
        public void EnglishGreeting(string name)
        {
            Console.WriteLine("Morning," + name);
        }
        public void GreetPeople(string name)
        {
            EnglishGreeting(name); // 做某些额外的事情,比如初始化之类,此处略
        }
         //.... B
        public void ChineseGreeting(string name)
        {
            Console.WriteLine("早上好, " + name);
        }
        public enum Language
        {
            English, Chinese
        }
        public void GreetPeople(string name, Language lang)
        {
            switch (lang)
            {        //做某些额外的事情,比如初始化之类,此处略  
                case Language.English:
                    EnglishGreeting(name);
                    break;
                case Language.Chinese:
                    ChineseGreeting(name);
                    break;
            }
        }
    }
}

2、

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace 委托    //方法调用方法
{
    public delegate void GreetingDelegate(string name);
    // static class GreetingDelegateMethod  // 定义一个静态类
    class GreetingDelegateMethod
    {
       // static public void GreetPeople(GreetingDelegate MakeGreeting, string name);//委托(MakeGreeting)定义的参数 是一个方法(静态)
        public void GreetPeople(GreetingDelegate MakeGreeting, string name)//委托定义的参数 是一个方法
        {
            MakeGreeting(name);//name 是方法的参数
        }
        public static void EnglishGreeting(string name)
        {
            Console.WriteLine(name+" Morning," );
        }
        public static void ChineseGreeting(string name)
        {
            Console.WriteLine(name + "   ,  早上好");
        }


    }
}

3、

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace 委托
{
    class Program
    {
        static void Main(string[] args)
        {
          //1、设置到 ABCD 类
            /* ABCD a = new ABCD();
               a.GreetPeople("Hui Jiang",ABCD.Language.English);
               Console.ReadKey();
            */
            //2、委托调用  设置 GreetingDelegateMethod

            /*GreetingDelegateMethod.GreetPeople(GreetingDelegateMethod.EnglishGreeting, "Hui Jiang ");
             GreetingDelegateMethod.GreetPeople(GreetingDelegateMethod.ChineseGreeting, " 蒋 辉");
              */
           
        GreetingDelegateMethod gdm = new GreetingDelegateMethod();
           /*   gdm.GreetPeople(GreetingDelegateMethod.ChineseGreeting, "蒋辉");
                gdm.GreetPeople(GreetingDelegateMethod.EnglishGreeting, "Hui Jiang");
            */
            
            
            //而既然委托GreetingDelegate 和 类型 string 的地位一样,都是定义了一种参数类型,那么,我是不是也可以这么使用委托?
               // A
              /*  string name1, name2;
                  name1 = "Hui Jiang ";
                  name2 = " 蒋辉 ";
                 gdm.GreetPeople(GreetingDelegateMethod.EnglishGreeting,name1);
                 gdm.GreetPeople(GreetingDelegateMethod.ChineseGreeting,name2);
              */
            //  B  而既然委托GreetingDelegate 和 类型 string 的地位一样,都是定义了一种参数类型,那么,
                 //我是不是也可以这么使用委托?以下为引用的内容:

            /* GreetingDelegate delegate1, delegate2;
             delegate1 = GreetingDelegateMethod.EnglishGreeting;
             delegate2 = GreetingDelegateMethod.ChineseGreeting;
             gdm.GreetPeople(delegate1,"Hui Jiang ");
             gdm.GreetPeople(delegate2, " 蒋辉 ");
           */
             
           /*如你所料,这样是没有问题的,程序一如预料的那样输出。这里,我想说的是委托不同于string的一个特性:
             可以将多个方法赋给同一个委托,或者叫将多个方法绑定到同一个委托,当调用这个委托的时候,
             将依次调用其所绑定的方法。在这个例子中,语法如下: 以下为引用的内容:*/
        /*  GreetingDelegate delegate1;
          delegate1 =GreetingDelegateMethod.EnglishGreeting;     // 先给委托类型的变量赋值
          delegate1 +=GreetingDelegateMethod.ChineseGreeting;     // 给此委托变量再绑定一个方法 
            
         // 将先后调用 EnglishGreeting 与 ChineseGreeting 方法
          gdm.GreetPeople(delegate1,"Hui Jiang "); */



           /* 实际上,我们可以也可以绕过GreetPeople方法,通过委托来直接调用EnglishGreeting和ChineseGreeting:

              以下为引用的内容:*/
            /* GreetingDelegate delegate1;//delegate1 其实就是一个方法 
             delegate1 =GreetingDelegateMethod. EnglishGreeting;     // 先给委托类型的变量(一个方法)赋值  
             delegate1 +=GreetingDelegateMethod. ChineseGreeting;     // 给此委托变量再绑定一个方法 
            */

            // 将先后调用 EnglishGreeting 与 ChineseGreeting 方法
            // delegate1("Hui Jiang ");      
          /*  注意这里,第一次用的“=”,是赋值的语法;第二次,用的是“+=”,是绑定的语法。如果第一次就使用“+=”, 将出现“使用了未赋值的局部变量”的编译错误。
           * 我们也可以使用下面的代码来这样简化这一过程: */

           /* GreetingDelegate delegate1 = new GreetingDelegate(GreetingDelegateMethod.EnglishGreeting);
             delegate1 += GreetingDelegateMethod.ChineseGreeting;       // 给此委托变量再绑定一个方法
             delegate1("Hui Jiang ");
            */
            //  取消绑定 在这里就不讲了 “ -+ ” 


        /*  尽管这样达到了我们要的效果,但是似乎并不美气, 光是第一个方法注册用“=”,第二个用“+=”就让人觉得别扭。此时,轮到Event出场了,
         * C# 中可以使用事件来专门完成这项工作, 那么我们就来定义 GreetingManager 类,它变成了这个样子:
         * 接下来就是  event(事件) 如果你不知道什么是事件,可以先去了解下事件的 最基本知识!*/


        //设置到 GreetingManager  类
            /*很容易注意到:MakeGreet 事件的声明与之前委托变量delegate1的声明唯一的区别是多了一个event关键字。看到这里,你差不多明白到:
             * 事件其实没什么不好理解的,声明一个事件不过类似于声明一个委托类型的变量而已。 */








        Console.ReadKey();
        }

    }
}

对于  事件    在这里 只能说  时间真的很晚了     下次总结  

今天 花了点时间  把事件 解决掉了       废话不多说   上代码!

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace 事件
{
    class Program
    {
        static void Main(string[] args)
        {
            Publishser pub = new Publishser();
            Subscriber sub = new Subscriber();
            pub.NumberChanged += new NumberChangedEventHandler(sub.OnNumberChanged);
            pub.DoSomething(); // 应该通过DoSomething()来触发事件
           // pub.NumberChanged(100); // 但可以被这样直接调用,对委托变量的不恰当使用
            Console.ReadKey();
        }
    }
    public delegate void NumberChangedEventHandler(int count); // 定义委托
    public class Publishser // 定义事件发布者
    {
        private int count;
      //   public NumberChangedEventHandler NumberChanged; // 声明委托变量
       public event NumberChangedEventHandler NumberChanged; // 声明一个事件
        public void DoSomething()
        {
            if (NumberChanged != null) // 在这里完成一些工作 ...
            { //满足某种条件  触发事件
                count++;
                NumberChanged(count);
                NumberChanged(100);//publishser内部调用
            }
        }
    }
    public class Subscriber     // 定义事件订阅者
    {
        public void OnNumberChanged(int count)
        {
            Console.WriteLine("Subscriber notified: count = {0}", count);
        }
    }
}

PS:

// ************************************************************************

上面代码定义了一个NumberChangedEventHandler 委托,然后我们创建了事件的发布者Publisher 和订阅者Subscriber。当使用委托变量时,客户端可以直接通过委托变量触发事件,也就是直接调用pub.NumberChanged(100),这将会影响到所有注册了该委托的订阅者。而事件的本意应该为在事件发布者在其本身的某个行为中触发,比如说在方法DoSomething()中满足某个条件后触发。通过添加event 关键字来发布事件,事件发布者的封装性会更好,事件仅仅是供其他类型订阅,而客户端不能直接触发事件(语句pub.NumberChanged(100)无法通过编译),事件只能在事件发布者Publisher 类的内部触发(比如在方法pub.DoSomething()中),换言之,就是NumberChanged(100)语句只能在Publisher 内部被调用。

大家可以尝试一下,将委托变量的声明那行代码注释掉,然后取消下面事件声明的注释。此时程序是无法编译的,当你使用了event 关键字之后,直接在客户端触发事件这种行为,也就是直接调用pub.NumberChanged(100),是被禁止的。事件只能通过调用DoSomething()来触发。这样才是事件的本意,事件发布者的封装才会更好。

就好像如果我们要定义一个数字类型,我们会使用int 而不是使用object 一样,给予对象过多的能力并不见得是一件好事,应该是越合适越好。尽管直接使用委托变量通常不会有什么问题,但它给了客户端不应具有的能力,而使用事件,可以限制这一能力,更精确地对类型进行封装。

 明:这里还有一个约定俗称的规定,就是订阅事件的方法的命名,通常为“On 事件名”,比如这里的OnNumberChanged

抱歉!评论已关闭.