zoukankan      html  css  js  c++  java
  • 【转】C#事件和委托的理解

    知乎大佬多系列

    作者:Junased
    链接:https://www.zhihu.com/question/28932542/answer/42769044
    来源:知乎


    感觉官方说法可以搜索到,我就说理解。
    先说结论(我的理解):声明一个事件,类似于声明一个进行封装了的委托。


    详细的:
    • 委托

    这个可以简单的理解为:把方法当成方法的参数
    看起来有点绕口,咱们先写个“你好,世界!”
    public void HelloWorld(string name)
    {
        ByEnglish(name);
    }
    public void ByEnglish(string name)
    {
        Console.WriteLine("Hello World By" + name);
    }
    先把这两个方法写出来,先别问为啥这么写
    好了,现在产品经理打算整个中文版的,好,咱改!
    public void ByChinese(string name)
    {
        Console.WriteLine("你好,世界!作者:" + name);
    }
    很明显,上面的HelloWorld()得改了
    public enum Language
    {
        English,CHinese
    }
    public void HelloWorld(string name,Language lan)
    {
        switch(lan)
        {
            case Language.English:ByEnglish(string name);break;
            case Language.Chinese:ByChinese(string name);break;
        }
    }

    差不多这样的话可以满足目前的需求了

    现在突然又蹦出来个意大利人想弄出个意大利版(我不会意大利语,不贴了),按照上面的思路,大概也能整出来。

    然后,产品经理说:这个方法咱要全球化,每个语言都要照顾到。(NMB)
    按照上面的思路来,我觉得可以抽刀砍人了。
    但是法律这玩意儿可怕哟,想到这个我的心儿就碎了。
    所以咱们还是把“委托”掏出来吧!
    委托上面的说的是:把方法当做方法的参数,大概就是这个样子
    public void HelloWorld(string name, 方法 方法名)
    
    上委托,把上面代码改了:
     1 private static delegate void HelloWorldDelete(string name)
     2 public void HelloWorld(string name, HelloWorldDelete chooseLanguage)
     3 {
     4     chooseLanguage(name);
     5 }
     6 private static void ByEnglish(string name)
     7 {
     8     Console.WriteLine("Hello World By" + name);
     9 }
    10 private static void ByChinese(string name)
    11 {
    12     Console.WriteLine("你好,世界!作者:" + name);
    13 }
    14 static void Main(string[] args)
    15 {
    16     HelloWorld("张三",ByChinese);
    17     HelloWorld("ZhangThree",ByEnglish);
    18 }
    View Code

    输出:
    你好,世界!作者:张三
    Hello World By ZhangThree

    再写个绑定版的(这回只写Main中的,因为其他的没变):
    static void Main(string[] args)
    {
        HelloWorldDelete delegateEnglish,delegateChinese;
        delegateEnglish = ByEnglish;
        delegateChinese = ByChinese;
        HelloWorld("张三",delegateChinese);
        HelloWorld("ZhangThree",delegateEnglish);
    }

    输出不变。

    换个姿势绑定(只写Main中的,因为其他的没变):
    static void Main(string[] args)
    {
        HelloWorldDelete delegateEnglish,delegateChinese;
        delegateEnglish = ByEnglish;
        delegateChinese = ByChinese;
        HelloWorld("张三",delegateChinese);
        HelloWorld("ZhangThree",delegateEnglish);
    }

    输出:
    Hello World By 张三
    你好,世界!作者:张三

    再换个体位(只写Main中的,因为其他的没变):
    static void Main(string[] args)
    {    
        HelloWorldDelete delegateAll;
        delegateAll = ByEnglish;
        //“=”表示赋值
        delegateAll += ByChinese;   //“+=”表示绑定,委托不能直接+=,会出现“未赋值              
                                    //什么的错误”;相应的“-=”表示解除绑定
        delegateAll ("张三");
    }


    • 事件

    写代码讲究个“说学逗唱”,说错了,讲究个“面向对象”。
    面向对象:封装、继承、多态。

    咱们就先从封装开始(我不会加二级标题):
    封装
    把上面的封装一下
    public delegate void HelloWorldDelegate(string name);
    public class HelloWorldClass
    {
        HelloWorldDelegate del;
        public void HelloWorld(string name)
        {
            if(del != null)    //有方法注册了
                del(name);     //委托调用所有注册的方法
        }
    }
    
    class Program
    {
        private static void ByEnglish(string name)
        {
            Console.WriteLine("Hello World By" + name);
        }
        private static void ByChinese(string name)
        {
            Console.WriteLine("你好,世界!作者:" + name);
        }
    
        static void Main(string[] args)
        {
            HelloWorldClass hw = new HelloWorldClass();
            hw.del = ByEnglish;
            hw.del += ByChinese;
            hw.HelloWorld("张三");
        }
    }

    输出:
    Hello World By 张三
    你好,世界!作者:张三

    可是我们回头一看,HelloWorldClass里面的东西根本没封装住,很明显del暴露了,不想暴露就得改成private,改了以后几乎就没用了。然后,我们很自然想到private字段、public属性,例如
    public class Number
    {
        private int num;
        public int Num
        {
            get { return; }
            set { num = value; }
        }
    }

    所以,把“事件”掏出来:
    事件:事件至于委托,类似于属性至于字段。不管声明成public还是protected,都是private的。

    修改上面代码
    public delegate void HelloWorldDelegate(string name);
    public class HelloWorldClass
    {
        public event HelloWorldDelegate del;
        public void HelloWorld(string name)
        {
       
            del(name);     //委托调用所有注册的方法
        }
    }
    
    class Program
    {
        private static void ByEnglish(string name)
        {
            Console.WriteLine("Hello World By" + name);
        }
        private static void ByChinese(string name)
        {
            Console.WriteLine("你好,世界!作者:" + name);
        }
    
        static void Main(string[] args)
        {
            HelloWorldClass hw = new HelloWorldClass();
            hw.del = ByEnglish;    //会出现编译错误
            hw.del += ByChinese;   //直接+=就好  
            hw.HelloWorld("张三");
        }
    }

    输出:
    你好,世界!作者:张三



  • 相关阅读:
    springboot2整合seata(AT模式)
    SpringBoot2整合minio
    Minio安装(docker)、初始密码及界面操作
    elasticsearch mapper创建
    elasticsearch 中文分词
    C++11:20weak_ptr弱引用的智能指针
    C++11:19unique_ptr独占的智能指针
    C++11:18shared_ptr共享的智能指针
    C++11:17可变参数模版和type_traits的综合应用
    C++11:16可变参数模板
  • 原文地址:https://www.cnblogs.com/fy26q/p/9634269.html
Copyright © 2011-2022 走看看