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

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

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

2.4 Action委托

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

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

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

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

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

            Action 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 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,大家一起探讨!
版权声明:本文为博主原创文章,转载请附上原文出处链接和本声明

你可能感兴趣的:(C#基础-委托事件-15)