C#基础-委托事件-15

"小伙子,红旗广场怎么走?"又一次被人叫住问路,换作以前,我一定会指一条相反的路告诉他,然后沾沾自喜感觉自己整到别人了。但是现在我没有,也许是过了幼稚的年纪,我耐心的告诉他:"前面过两个红绿灯,第二个十字路口左转,再走五十米会看到一个步行街。……那条街上人多,你问问他们怎么走。"


========================手动分割线==========================

一、委托

  • 委托是一个类型安全的对象,它指向程序中另一个以后会被调用的方法(或多个方法)。
  • 通俗的说,委托是一个可以引用方法的对象,当创建一个委托,也就创建一个引用方法的对象,进而就可以调用那个方法,即委托可以调用它所指的方法。
  • 委托的使用步骤:

1、定义委托类型(数据类型)

        [访问修饰符] delegate 返回类型 委托名(形参);

2、声明委托对象(变量、属性)

        委托名 委托实例名;

3、创建委托对象(确定与哪些方法进行绑定)
等价于:委托实例名 = 某个类的方法

        委托实例名=new 委托名(某个类的方法) 

4、使用委托对象调用方法
委托实例名(实参)

  • 委托注意事项:
    1、委托和方法必须具有相同的参数。
    2、委托可以调用多个方法,即一个委托对象可以维护一个可调用方法的列表而不是单独的一个方法,称为多路广播(多播)。
    3、使用+=和-=运算实现方法的增加和减少
using System;

namespace Lesson13
{
    //第一步:委托的声明
    public delegate void BuyFood (string food);

    //创建男人类
    class Man
    {
        //定义一个买食物的方法
        public static void BuyBananer (string food)
        {
            Console.WriteLine ("伟华又去买" + food);
        }
    }

    class Woman
    {
        public static void BuyMilk (string food)
        {
            Console.WriteLine ("不是每一滴牛奶都叫" + food);
        }

        public static void BuyGua (string food)
        {
            Console.WriteLine ("男朋友漏电了,帮我买根{0}吧", food);
        }
    }

练习:小华和小超是一对让人羡慕的基佬,
1、在一个风和日丽的中午,小华给超越说:“人家想买一件坏坏的衣服”。
2、晚上,小华饿了,但是又不想自己去做饭,就让小超去做饭吧
3、有一天,小华劈腿了,劈腿给了小雨,以后宵夜就由小雨负责了

    class Weihua
    {
        //买衣服
        public void BuyClothes (string clothes)
        {
            Console.WriteLine ("我是小华,我想买一件" + clothes);
        }
        //添加一个做饭的委托命令
        public delegate void OrderPerson (string order);
    }

    class Chaoyue
    {
        public static void Cook (string food)
        {
            Console.WriteLine ("我是小超,我给小华" + food + "吃");
        }

        public static void Clothes (string clothes)
        {
            Console.WriteLine ("我是小超,我给小华买了一件" + clothes);
        }
    }

    class Chunyu
    {
        //添加做饭的方法
        public static void Cook (string food)
        {
            Console.WriteLine ("我是小雨,我给小华" + food + "吃");
        }
    }
  • 定义一个委托,用来演示匿名委托
    public delegate void TestDelegate (string str);
  • 定义一个委托,用来实现将小写字母转成大写字母
    public delegate void UpperDelegate ();
  • 定义一个委托,用来演示lambda表达式类型
    public delegate void SumDelegate (int a,int b);
  • 定义一个委托,来实现两个数的交换
    public delegate void ChangeNumDelegate (ref int a,ref int b);
    class MainClass
    {
        public static void Main (string[] args)
        {
            //第二步:声明委托对象
            BuyFood buy, buy1, buy2;
            //第三步:创建委托对象
            buy1 = new BuyFood (Man.BuyBananer);
            //第四步:使用委托对象调用方法
            buy1 ("香蕉");
  • 委托绑定
  • 使用 "=" 绑定方法,会覆盖,使用“+=”绑定方法,不会覆盖
            buy2 = Woman.BuyMilk;
            buy2 ("特仑苏");

            //buy = buy1 + buy2;//或者
            buy = buy1;
            buy += buy2;
            buy ("黄瓜");
  • 创建对象小华,调用买衣服的方法
            Weihua weihua = new Weihua ();
            weihua.BuyClothes ("坏坏的衣服");
  • 声明委托对象,并指定小超为代理人
            Weihua.OrderPerson order = Chaoyue.Clothes;
            //委托开始执行
            order ("小皮鞭");

            Console.WriteLine ("晚上了,小华感觉好饿啊");
            //命令下达给代理人小超去做饭
            order = Chaoyue.Cook;
            //小超开始做饭
            order ("下面");
            Console.WriteLine ("小华在劈腿给小雨后的一个晚上,突然又饿了");
            //这时候小雨成了给小华做饭的代理人
            order = Chunyu.Cook;
            //开始做饭了
            order ("火腿肠");

二、委托的其他四种形式

2.1 匿名委托 -相当于绑定了没有方法名的方法

  • 格式:
    委托名 变量名 = delegate (参数类型1 参数名1, ...) {
    语句;
    };
  • 参数:相当于绑定方法的形参
  • {}里面的东西相当于绑定方法的方法体
  • 由于是赋值的过程,实质是一个语句,后面;不能省略
            TestDelegate niming = delegate(string food) {
                Console.WriteLine ("好吃不过" + food);
            };
            niming ("饺子");

练习:使用匿名委托,实现将传入的字符串中小写字母,转成大写字母的字符串

            UpperDelegate upDele = delegate() {
                Console.WriteLine ("请输入:");
                string input = Console.ReadLine ();
                Console.WriteLine (input.ToUpper ());
            };
            upDele ();

2.2 lambda表达式类型的委托

  • 格式:(参数)=> {要执行的代码};
    1、参数:相当于要绑定的方法的参数
    2、=>:是lambda表达式的一个操作符,在左边定义一个参数列表,右边操作这些参数,=>前是参数, =>后是方法语句
    3、{};里面相当于绑定方法的方法体
  • 注意:不要忘了语句后的;
            SumDelegate sumDele = (int a, int b) => {
                Console.WriteLine ("a + b = {0}", a + b);
            };
            sumDele (3, 5);

练习:使用lambda表示类型的委托,来实现两个整数的交换

            ChangeNumDelegate changeNumDele = (ref int a,ref int b) => {
                int temp = a;
                a = b;
                b = temp;
            };
            int aa = 3;
            int bb = 5;
            changeNumDele (ref aa, ref bb);
            Console.WriteLine ("交换后的值为:aa = {0},bb={1}", aa, bb);

2.3 Func委托

  • 格式:
              Func<int,int,int> func = delegate(int a,int b){
                    return  int;
              }
  • 使用Func泛型,前面两个是参数类型,后面一个表示返回值类型,其变量可以绑定匿名委托,Lambda表达式和相同类型的方法
  • 注意:这种委托,一定会有返回值
            Func<int,int,int> s = delegate(int a, int b) {
                return a * b;
            };
            Console.WriteLine (s (2, 3));

            Func<int> ss = delegate() {
                Console.WriteLine ("我就不带参数");
                return 2;
            };
            ss ();

            //使用Func泛型实现一个返回两个数的和,使用Lambda表达式
            Func<int,int,int> sumFunc = (int num1, int num2) => {
                return num1 + num2;
            };
            Console.WriteLine ("和为:" + sumFunc (8, 9));

2.4 Action委托

  • 格式:
              Action<参数类型1, ..., 参数类型n> = delegate(参数类型1 参数名, ..) {
                语句;
              };
  • 使用Action泛型的委托,<>里面放的是参数类型
  • 这种类型的委托可以绑定匿名委托,Lambda表达式和方法
  • 注意:这种委托不能有返回值
            Action<string> action = (string str) => {
                Console.WriteLine ("我床塌啦" + str);    
            };
            action ("今晚可以去你那吗");

练习:使用Action委托,实现将一个数扩大2倍

            Action<int> mul = (int a) => {
                Console.WriteLine (a * 2);
            };
            mul (9);

综合练习:
1.通过委托实现, 创建一个具有n个元素的整数数组
2.通过委托实现, 对数组的元素进行随机赋值, 取值范围[m, n]
3.通过委托实现, 对数组进行冒泡排序, 可以控制排序规则(从小到大, 或 从大到小)

            Func<int, int[]> r1 = delegate(int n) {
                return new int[n];
            };
            //Func<int, int[]> r1 = n => new int[n];

            Action<int[], int, int> r2 = delegate(int[] array, int m, int n) {
                Random r = new Random ();
                for (int i = 0; i < array.Length; i++) {
                    array [i] = r.Next (m, n + 1);
                }
            };

            Action<int[], bool> r3 = delegate(int[] array, bool flag) {
                for (int i = 0; i < array.Length - 1; i++) {
                    for (int j = 0; j < array.Length - 1 - i; j++) {
                        //判断升序(true),降序(false)
                        if (flag) {
                            //升序
                            if (array [j] > array [j + 1]) {
                                int temp = array [j];
                                array [j] = array [j + 1];
                                array [j + 1] = temp;
                            }
                        } else {
                            //降序
                            if (array [j] < array [j + 1]) {
                                int temp = array [j];
                                array [j] = array [j + 1];
                                array [j + 1] = temp;
                            }
                        }
                    }
                }
            };

            int[] arr = r1 (10);
            r2 (arr, 10, 100);
            r3 (arr, false);
            for (int i = 0; i < arr.Length; i++) {
                Console.Write (arr [i] + " ");
            }
            Console.WriteLine ();

三、事件

事件其实没什么不好理解的,声明一个事件不过类似于声明一个进行了封装的委托类型的变量而已。使用事件不仅能获得比委托更好的封装性以外,还能限制含有事件的类型的能力。这是什么意思呢?它的意思是说:事件应该由事件发布者触发,而不应该由事件的客户端(客户程序)来触发
1、将委托封装到类的内部
2、发送(或引发)事件的类叫做发行者,接收(处理)事件的类叫订阅者

  • 注意:事件的触发必须在发行者的内部,客户端不能触发
  • 使用步骤:
    1、声明委托
    2、声明事件
    3、创建接收者
    4、绑定事件
    5、通知接收者,执行方法
//定义一个类,作为事件的发送者
    class GreetingManager
    {
        //声明一个委托
        public delegate void Greeting (string name);
        //声明一个事件,类型就是上面的委托类Greeting
        public event Greeting MakeGreet;

        public void GreetPeople (string name, string str, int aa)
        {   
            //触发上面的定义的事件,并传入参数
            MakeGreet (name);
        }
    }

    //定义一个类,作为事件的订阅者
    class Program
    {
        //添加方法
        public static void Taiguo (string name)
        {
            Console.WriteLine ("沙瓦迪卡," + name);
        }

        public static void Yingguo (string name)
        {
            Console.WriteLine ("哈喽," + name);
        }
    }
            //创建一个事件发送者对象
            GreetingManager greetManager = new GreetingManager ();
            //绑定事件
            greetManager.MakeGreet += Program.Taiguo;
            greetManager.MakeGreet += Program.Yingguo;
            greetManager.MakeGreet -= Program.Taiguo;
            //通知接受者,执行方法
            greetManager.GreetPeople ("美女", "ss", 234);

练习:发微博, 创建一个类作为微博的发布者(博主),类中有一个发微博的委托,在类中声明发微博的事件,在类中添加发微博的方法,在方法中判断如果有人注册了这个事件,就去通知注册的人,博主发微博了,同时添加三个粉丝类,为博主添加粉丝

    // 发布者(博主)
    class Bloger
    {
        //声明一个发微博的委托
        public delegate void PublicBlogDelegate ();
        //声明发微博的事件
        public event PublicBlogDelegate Output;
        //添加发微博的方法
        public void PublicBlog ()
        {
            //开始发微博,之前都是发微博之前的准备
            Console.WriteLine ("博主:\n 突然好想做一首诗啊\n");

            //如果有人关注了博主,就通知粉丝
            if (Output != null) {
                Console.WriteLine ("微博后台:\n 赶紧去通知粉丝\n");

                //通知订阅者们(粉丝们)
                Output ();
            }
        }
    }
    // 订阅者1(粉丝1)
    class User1
    {
        public static void Comment1 ()
        {
            Console.WriteLine ("一楼评论:楼主SB");
        }
    }

    class User2
    {
        public static void Command2 ()
        {
            Console.WriteLine ("二楼评论:二楼是SB");
        }
    }

    class User3
    {
        public static void Command3 ()
        {
            Console.WriteLine ("三楼评论:自古人才出二楼");
        }
    }
  • 在main函数中添加:
            //创建博主类对象
            Bloger bloger = new Bloger ();
            //为博主添加粉丝
            bloger.Output += User1.Comment1;
            bloger.Output += User2.Command2;
            bloger.Output += User3.Command3;
            //博主发微博
            bloger.PublicBlog ();

本次讲解就到这里,有关技术问题请小伙伴们添加QQ群:941928511,大家一起探讨!
版权声明:本文为博主原创文章,转载请附上原文出处链接和本声明

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容