深刻浅出之委托

1、什么是委托git

        源码下载安全

       1.委托是面向对象的、类型安全的,是引用类型。使用delegate关键字进行定义。委托的本质就是一个类,继承自System.MulticastDelegate,而它又派生自System.Delegate。里面内置了几个方法 ,能够在类的外面声明委托,也能够在类的内部声明委托。ide

对委托的使用:先定义,后声明和实例化委托,而后做为参数传递给方法。学习

2、委托定义编码

       1.委托就是一个类,别把它想成了方法,因此不能重载。委托也不能继承由于是密封类。spa

namespace MyDelegation
{
    /// <summary>
    /// 委托
    /// </summary>
    //定义来了一个全局的委托 无参无返回值
    //特色就是在本类的全部方法调用
    public delegate void MyDelegate();

    /// <summary>
    /// 1:这里的无参,无返回值,表示传递的方法是一个没有参数,没有返回值的方法。
    /// 2:委托就是一个类,别把它想成了方法,因此不能重载。委托也不能继承由于是密封类。
    /// 3:不要在方法使用委托,委托在传递此方法。
    /// </summary>
    public class MyDelegationDeom
    {

        /// <summary>
        /// 无参无返回值
        /// </summary>
        public delegate void MyDelegate();

        /// <summary>
        /// 有参无返回值
        /// </summary>
        public delegate void MyDelegat1(int x);

        /// <summary>
        /// 有参有返回值
        /// </summary>
        public delegate int MyDelegate2(int x);

        /// <summary>
        /// 无参有返回值
        /// </summary>
        public delegate int MyDelegate3();

        /// <summary>
        /// 泛型委托
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="t"></param>
        public delegate void MyDelegate<T>(T t);

        /// <summary>
        /// 方法
        /// </summary>
        public void Show()
        {
            //MyDelegate myDelegate = new MyDelegate(Show);
            //myDelegate.Invoke();
            Console.WriteLine("Hello World!");
        }

    }
}
View Code

3、委托的声明与使用.net

       1.实例化声明,等于声明,多播声明。传入方法的方式(普通方法,还能够传入静态、实例方法,匿名方法),实例传入 方法不须要带()。code

                //传入方法的方式(普通方法,还能够传入静态、实例方法,匿名方法)
                //实例传入 方法不须要带()
                MyDelegate myDelegate = new MyDelegate(new MyDelegationDeom().Show);
                myDelegate();
                //省略实例 能够直接等于可是效果是同样的
                MyDelegate myDelegate1 = new MyDelegationDeom().Show;
                myDelegate1();
                //多播委托 委托链实现了,将委托用链链接起来,执行的使用从头至尾执行
                MyDelegationDeom myDelegationDeom = new MyDelegationDeom();
                MyDelegate myDelegate2 = new MyDelegationDeom().Show;
                myDelegate2 += myDelegationDeom.Show;
                //多播委托也能够删除,只要将对应的实例方法放入就能够删除以前的添加方法
                myDelegate2 -= myDelegationDeom.Show;
                myDelegate2 -= new MyDelegationDeom().Show;
                myDelegate2.Invoke();
View Code

       2.委托方法调用,可使用Invoke()方法,或者直接使用委托实例()。对象

//委托调用方式
            {
                MyDelegate myDelegate1 = new MyDelegationDeom().Show;
                //调用Invoke方法 
                myDelegate1.Invoke();
                //直接调用  
                //和上面两个方法一致的效果,也有一步调用方法。
                myDelegate1();
            }
View Code

       3.多播委托是最为特殊的可使用+=、-=进行添加委托链,顾名思义就是添加一个委托,删除一个委托(若是删除没有找到对应的委托不会报错)下面的代码中咱们先添加了两个方法进入委托,而后使用-=删除了两个方法咱们执行仍是执行了一个方法。这个是为何呢小老弟?大家以为是什么问题?blog

                //多播委托 委托链实现了,将委托用链链接起来,执行的使用从头至尾执行
                MyDelegationDeom myDelegationDeom = new MyDelegationDeom();
                MyDelegate myDelegate2 = new MyDelegationDeom().Show;
                myDelegate2 += myDelegationDeom.Show;
                //多播委托也能够删除,只要将对应的实例方法放入就能够删除以前的添加方法
                myDelegate2 -= myDelegationDeom.Show;
                myDelegate2 -= new MyDelegationDeom().Show;
                myDelegate2.Invoke();
View Code

 

         4.上面咱们使用多播委托的时候在+=方法的时候使用new MyDelegationDeom().Show 咱们都知道New建立的对象都是不一样的,因此在下面删除的时候找不到,就不能删除对应的委托了。

         5.咱们能够明显的发现new MyDelegationDeom().Show这个方法使用一次还要去定义方法,会使代码冗余、繁琐。在不断的简化中产生了lambda表达式,lambda表达式就是方法的缩写,简化的顺序就是从上往下,执行的效果和做用与以前的同样。

 

MyDelegate myDelegate4 = new MyDelegate(() => { Console.WriteLine("哈哈"); });
                myDelegate4.Invoke();
                MyDelegate myDelegate5 = () => { Console.WriteLine("哈哈"); };
                myDelegate5.Invoke();
                MyDelegate myDelegate6 = () => Console.WriteLine("哈哈");
                myDelegate6.Invoke();
                //有参无返回值
                MyDelegate1 myDelegate7 = (x) => Console.WriteLine("哈哈");
                myDelegate7.Invoke(5);
                MyDelegate1 myDelegate8 = x => Console.WriteLine("哈哈");
                myDelegate8.Invoke(5);
                //有参有返回值 若是是两个参数的话就必定要加()了。
                MyDelegate2 myDelegate9 = x => x;
                myDelegate9.Invoke(5);
View Code

3、委托情景对话

         1.假如咱们有一个数据集合咱们须要过滤成绩大于200分和学生名字长度大于2的学生,各位大家的作法是否是和我下面写的同样呢?小老弟

    /// <summary>
    /// 学生类
    /// </summary>
    public class Student
    {
        /// <summary>
        /// 主键
        /// </summary>
        public int ID { get; set; }
        
        /// <summary>
        /// 名称
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 成绩
        /// </summary>
        public int Score { get; set; }
    }
View Code
//假如咱们有一个数据集合咱们须要过滤成绩大于200分的学生
                //总数据源
                List<Student> data = new List<Student>();

                //须要拿出来的数据
                List<Student> students = new List<Student>();
                //赛选数据
                data.ForEach(x =>
                {
                    if (x.Score > 200)
                    {
                        students.Add(x);
                    }
                    else if (x.Name.Length > 2)
                    {
                        students.Add(x);
                    }
                });
View Code

         2.可是忽然有一天产品粑粑说我要改需求,老师能够动态的选中筛选条件?咱们第一时间会感受我是谁,我在哪里,我在作什么?怀疑完以后咱们仍是要想解决方案去作,刚刚你们既然已经学习了委托,咱们知道委托能够动态传递方法。那么咱们是否是能够将判断条件放到外面去作,咱们将公共的代码复用呢?

        /// <summary>
        /// 定义一个委托 有参有返回值 咱们首先定义一个委托,参数是学生,返回的bool
        /// </summary>
        public delegate bool MyDelegateDecide(Student student);
            //只须要改变委托的传值,其余的不要修改了,加入知足了某个条件咱们就添加某个判断。
            MyDelegateDecide myDelegateDecide = x => x.Score > 200;
            myDelegateDecide += x => x.Name.Length > 2;
            //委托解耦
            {
                //假如咱们有一个数据集合咱们须要过滤成绩大于200分的学生
                //总数据源
                List<Student> data = new List<Student>();
                GetData(data, myDelegateDecide);
            }
/// <summary>
        /// 获取数据源
        /// </summary>
        /// <param name="data"></param>
        /// <param name="myDelegateDecide"></param>
        static List<Student> GetData(List<Student> data, MyDelegateDecide myDelegateDecide)
        {
            //须要拿出来的数据
            List<Student> students = new List<Student>();
            //赛选数据
            data.ForEach(x =>
            {
                if (myDelegateDecide.Invoke(x))
                {
                    students.Add(x);
                }
            });
            return students;
        }
View Code

4、委托渐入佳境(Action、Func 委托)

        1.Action是一个有参无返回值的委托  ,Func是一个有参而且有返回值的委托,共同点就是,都有默认最多16个参数,若是之后还想17就须要本身从新这个类。

      2.首先说一下为何咱们在日常开发中基本不会本身定义委托了,若是看了GetData的代码,咱们明显的发现,咱们定义的委托类型就写死了,不方便之后的灵活使用.net 就给咱们提供了两个标准委托。

        3.好处,咱们使用起来会更加方便,统一了咱们委托编码的规范 。

{
                Action action = () => { Console.WriteLine("无参无返回值"); };
                action.Invoke();
                Action<int> action1 = x => { Console.WriteLine("有参无返回值"); };
                action1.Invoke(5);
                Action<int, int> action2 = (x, y) => { Console.WriteLine("有参无返回值"); };
                action2.Invoke(1,2);
                Func<int, bool> func = x => true;
                func.Invoke(5);
            }
View Code

5、这不是和委托常常一块儿出现的事件吗?

         1.事件的定义,咱们能够很清楚的看到,定义事件咱们先要定义一个委托,而后在使用event定义事件。各位道友是否是感受事件好像就是委托的一个实例呢?

         2.事件不能再声明事件之外的地方调用方法Invoke 、已经不能直接修改事件的方法,只能+= 防止别人修改内部代码 private 继承都没有用。

         3.事件 重点:委托和事件的区别就在,事件是委托的实例

        /// <summary>
        /// 定义一个委托 无参无返回值
        /// </summary>
        public delegate void MyMaoDeom();

        /// <summary>
        /// 事件 委托和事件的区别就在,事件是委托的实例
        /// </summary>
        public event MyMaoDeom MyMaoDeomEvent;

6、事件情景(观察者模式)

        1.小兰有一只猫,当它叫的时候会,发生飞、跑、游泳的动做

/// <summary>
        /// 猫叫了发生动做
        /// </summary>
        public void Call()
        {
            Console.WriteLine("猫叫了发生动做");
            Movement movement = new Movement();
            movement.Fly();
            movement.Run();
            movement.Swimming();
        }

   2.咱们刚开始可能会这样写,直接写一个方法调用下面的动做,可是有一个咱们正在吃着泡面改着bug产品粑粑说不行这个需求须要修改,当小兰的猫叫的时候我想先游泳、而后跑、在而后小兰的猫就飞走啦。相信你们看着产品粑粑眼神从蒙圈,再到了惊讶,而后在苦苦哀求产品粑粑放过咱们把。

//事件 重点:委托和事件的区别就在,事件是委托的实例
            //事件不能再声明事件之外的地方调用方法Invoke 、已经不能直接修改事件的方法,只能+= 防止别人修改内部代码
            {
                //这个是直接调用的模式,可是缺点就是下次猫叫发生的动做想要发生变化的时候就须要
                //修这个类的方法,麻烦为了方便往后维护,咱们须要将之后须要改动的东西抽了出来
                Miao miao = new Miao();
                miao.Call();

                //这里的话咱们要使用事件来进行
                //这里其实就是一个典型的观察者模式,就是使用事件多播,达到动态的执行一些动做
                //不少地方都使用了这样的思想。
                Movement movement = new Movement();
                miao.MyMaoDeomEvent += movement.Swimming;
                miao.MyMaoDeomEvent += movement.Fly;
                miao.MyMaoDeomEvent += movement.Run;
                miao.CallNew();
            }
/// <summary>
        /// 猫叫了发生动做
        /// </summary>
        public void CallNew()
        {
            Console.WriteLine("猫叫了发生动做");
            Movement movement = new Movement();
            if (MyMaoDeomEvent != null)
            {
                MyMaoDeomEvent.Invoke();
            }
        }

最终咱们使用了咱们今天所学习的事件,实现了产品粑粑的需求。(这里你们可能会问为何咱们不用委托呢?这里使用事件主要是防止他人在外面对委托进行修改,为了安全保障。因此才会出现事件的。)

7、善始善终

       1.今天咱们学习了委托,相信你们和我同样都会有本身的收获,在这一段时间里咱们发现了不少时候,咱们写的代码都是同样的,可是就不一样于有的代码很简洁,有的代码很冗余,咱们要有一种将重复的东西封装将(不能够控制、常常变的数据)分离出来使用动态的手段进行传递。

相关文章
相关标签/搜索