zoukankan      html  css  js  c++  java
  • 委托

    注:以下文章仅为学习笔记,很大部分来自于他人博客或资料,我会相应注明,仅为学习。

    一、为什么要有委托

      要学习委托,我们首先要明白为什么要有委托,委托的意义在于什么。

      下面是来自于黑马论坛上某人的通俗解说,我觉得很好:

        1,当你需要把一个方法传送给其他方法时,可以考虑使用委托。好像不是很好理解;
        2,也可以这样说,当你确定要处理一件事,但又不能确定处理方法时,可以考虑用委托。
        3,其实单独的说委托的应用好像有点牵强,委托更多的是在事件中的应用。
        4,举个例子吧,目的是理解委托的原理,
        [  
           你想要吃饭,
           但是自己又不会做;//(委托方不知道实现细节),
           你计划找个小吃店,叫个西红柿牛腩盖饭;//(定义了一个委托)
           你决定找常去的那家叫做XXX的小吃店(实例化一个委托)
           你打电话给XXX小吃店;//(委托调用)
           XXX小吃店给你做好了你定的西红柿牛腩;//(代理函数工作)
           饭来了,真好。//委托执行结束
        ]

      我在博客园上看到一个引入委托的例子,很形象,讲的是主管监视员工是否玩游戏的故事,非常好的说明了委托的好处,这里我将举另一个例子,这个就大家自己去关注他的博客吧:http://www.cnblogs.com/superpcer/archive/2011/06/06/2073751.html

    二、委托的好处(不谈事件)

      1、将方法作为参数传递,降低代码间的耦合度

      2、让代码更加的简单,降低复杂度,增加重用性。

      3、委托可顺序的执行所封装的方法

    二、委托的解释

      委托(delegate)是一种包装方法调用的类型。就像类型一样,可以在方法之间传递委托实例,并且可以像方法一样调用委托实例。匿名函数是一个“内联”语句或表达式,可在需要委托类型的任何地方使用。可以使用匿名函数来初始化命名委托,或传递命名委托(而不是命名委托类型)作为方法参数。

    三、实例

      以下我用到的例子来自于:http://nt.discuz.net/showtopic-130142.html

      下面的例子是对学生信息按照学生的不同属性进行排序。

      首先我们新建一个Student类:

    public class Student {
            //这里为了简便就不用属性了
            public int id;
            public string name;
            public int age;
            public int classId;//假设有一个班级编号
            public Student(int id, string name, int age, int classId)
            {
                this.id = id;
                this.name = name;
                this.age = age;
                this.classId = classId;
            }
    }

    新建一张aspx的页面,拖一个按钮和一个Label,双击产生相应代码

    <asp:Button ID="Button2" runat="server" Text="委托排序" onclick="Button2_Click" />
    <br />
    <asp:Label ID="Label2" runat="server" Text=""></asp:Label>

    在相应代码中new一些Student的数组成员出来

    protected void Button2_Click(object sender, EventArgs e)
    {
                //声明一个Student的数组
                //为什么不用List或者List<T>呢,因为二者都是微软封装好的数据结构,实现了排序,没必要我画蛇添足
                Student[] s ={new Student(1004,"成成",19,4),
                             new Student(1002,"张才",22,1),
                             new Student(1003,"李大为",20,4),
                             new Student(1005,"冰冰",23,5),
                             new Student(1001,"李晓红",21,3),
                            };
    }

    假设我们按照id来对s排序,写出冒泡排序法sort(Student[] s);

            //实现冒泡排序法
            private void Sort(Student[] s)
            {
                for(int i =0; i < s.Length-1; i++)//控制轮数
                {
                    for(int j =0; j < s.Length-1- i; j++)//控制交换次数
                    {
                        if(s[j].id > s[j +1].id)
                        {
                            Student temp = s[j];
                            s[j]= s[j +1];
                            s[j +1]= temp;
                        }
                    }
                }
            }

    然后在相应函数中添加

    Sort(s);//完成排序

    但是,我们现在又想根据age排序,怎么办呢,当然,我们可以复制粘贴sort()方法,修改比较方法或者使用switch来判断用什么属性排序:

            //实现冒泡排序,通过不同的属性排序
            private void Sort(Student[] s,string sortfield)
            {
                switch (sortfield)
                {
                    case "id":
                        for (int i = 0; i < s.Length - 1; i++)//控制轮数
                        {
                            for (int j = 0; j < s.Length - 1 - i; j++)//控制交换次数
                            {
                                if (s[j].id > s[j + 1].id)//根据id排名
                                {
                                    Student temp = s[j];
                                    s[j] = s[j + 1];
                                    s[j + 1] = temp;
                                }
                            }
                        }
                        break;
                    case "age":
                        for (int i = 0; i < s.Length - 1; i++)//控制轮数
                        {
                            for (int j = 0; j < s.Length - 1 - i; j++)//控制交换次数
                            {
                                if (s[j].age > s[j + 1].age)//根据age排名
                                {
                                    Student temp = s[j];
                                    s[j] = s[j + 1];
                                    s[j + 1] = temp;
                                }
                            }
                        }
                        break;
                }
            }

    该方法的调用为,在响应函数中添加:

    Sort(s, "id");//根据id排名
    Sort(s, "age");//根据age排名

    但是,我们又想用classid排序(不和理),这样我们就需要添加一个case,copy代码,这样做代码重用性不高。现在可以考虑用委托。将比较大小的代码提炼成方法,我们在改变排序的属性时,只需要添加一个新方法即可,不需要修改既有代码。

            //使用委托,当然这种可以用泛型来解决
            public delegate bool CompareDelegate(Student s1, Student s12);//声明委托
            private void Sort(Student[] s,CompareDelegate method)//提供实现方法,在方法中的参数中包含委托实例方法(相当于实例化委托),该方法可以另外添加。
            {
                for (int i = 0; i < s.Length - 1; i++)//控制轮数
                {
                    for (int j = 0; j < s.Length - 1 - i; j++)//控制交换次数
                    {
                        if (method(s[j],s[j+1]))//根据age排名
                        {
                            Student temp = s[j];
                            s[j] = s[j + 1];
                            s[j + 1] = temp;
                        }
                    }
                }
            }
            private bool CompareById(Student s1, Student s2)
            {
                return s1.id > s2.id;
            }
            private bool CompareByAge(Student s1, Student s2)
            {
                return s1.age > s2.age;
            }

    该方法的调用为,在响应函数中添加

    //委托实现
    Sort(s,CompareById);
    for (int i = 0; i < s.Length; i++)
    {                 
      Label2.Text
    +=s[i].id+","+s[i].name+","+s[i].age+","+s[i].classId+"<br/>"; }

    即,调用了根据id排序的方法。

    运行结果就不添加了。

    四、实现委托的步骤

      来源参照:http://blog.csdn.net/huomm/article/details/1897010

      1、 先声明个委托实例  ;

          2、然后提供要处理的方法;

          3、再实例化委托(把委托看作是类的话,实例化委托就不难理解了,其参数是要处理的方法,这里的方法 不用加括号,实例化的过程就是装载方法的过程,就好像需要参数的构造函数一样)实例化后的委托对象就好比是c++中的指针,它本身就是封装了方法的对象;

          4、最后我们调用委托对象就好比是调用了被封装方法本身,调用时的参数也就传给了被封装的方法。

      5、需要注意的是 所声明的委托无论是 参数个数,参数类型,返回值类型 都要和所要封装的方法保持一致,当调用委托实例对象时,所传入的参数也要保持一致 ,否则会出现错误。 

    五、委托链

      我们知道委托是对方法的封装,而且委托可以封装很多方法形成委托链,其实委托就好像是一个容器,他封装了我们想要实现的若干方法,当调用委托对象(相当于c++中的指针)时,就会顺序的执行它所封装的所有的方法,如果有返回值的话,往往返回的是最后一个被执行的方法的返回值,委托链的形成可以用"+="或"-="对不同的委托实例进行二元操作。

      详细例子参照:http://blog.csdn.net/huomm/article/details/1897010

    六、总结:

      委托是一种引用类型,我们在处理他的时候要当作类来看待而不是方法,说白了委托就是对方法或者方法列表的引用,调用一个委托实例就好像是调用c++中的指针一样,他封装了对制定方法的引用,或者说委托起到的是桥梁的作用,实例后的委托对象会将给定的参数传递给他所回调的方法,并去执行方法。

  • 相关阅读:
    初学 Delphi 嵌入汇编[13] 地址参数用 [] 取值
    初学 Delphi 嵌入汇编[17] 逻辑运算
    初学 Delphi 嵌入汇编[11] 用汇编重写一个 Delphi 函数
    初学 Delphi 嵌入汇编[12] 在汇编代码中可以直接使用 Result
    初学 Delphi 嵌入汇编[19] Delphi 的无符号整数类型
    分享:tcpproxy实现
    Socket编程之简单介绍 蓝天下的雨 博客园
    分享:libuv 中文编程指南
    分享:《编程之美》求二叉树中节点的最大距离
    CentOS6.0下编译最新版本boost库
  • 原文地址:https://www.cnblogs.com/huangbx/p/2619161.html
Copyright © 2011-2022 走看看