【转】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("张三");
    }
}

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



猜你喜欢

转载自www.cnblogs.com/fy26q/p/9634269.html