学习和理解C#的委托

  去年自学C#用的教程是入门级的《学通C#的24堂课》,教材里面也没有提到委托和事件,工作中也没怎么用到。后来一次在网上看了一些大牛的博客,读完之后感觉懵懵懂懂,似懂非懂,过了两三天之后,却又全然忘记了。毕竟学习这事,温故而知新,学了不用,自然忘得也很快。对于如我一样的初学者来说,较好地理解委托和事件并是一件容易的事。其实掌握了的人,会觉得也没什么,而没有掌握的人,每次见到委托和事件就会觉得很畏惧。前段时间看到张旭亮老师的博客中关于.NET 开发系列PPT中提到一个观点,没学会委托就等不会.NET。我深受激励,所以这次下定决心认认真真学习了一下,并将自己的一些理解记录下来。

   委托,字面上的意思就是请别人帮忙做一些事情。读完文章之后你会发现,委托是指向一个方法的指针,通过指定一个委托名称,即可通过委托来调用方法。实际上与字面意思差不多。

  什么情况下适合使用委托

  首先通过一个例子来说明什么情况下使用委托。

  以学生值日为例,值日生要做开门、擦黑板的工作。对应的方法形式如下:

public void OpenDoor(){
    //开门具体实现
    ...
}

public void CleanBlackBoard(){
    //擦黑板具体实现
    ...
}

  下面再写一个值日的方法,要完成上述这些工作:

public void OnDuty(){
    OpenDoor();
    CleanBlackBoard();}

  这样,值日生开门、擦黑板的工作就实现了。但是这种方法的扩展性和灵活性不是很好,假设现在值日生工作又增加了,需要关灯,方法如下:

public void TurnOffLight(){
    //关灯的具体逻辑
    ...
}

  我们就需要修改OnDuty方法:

public void OnDuty(){
    OpenDoor();
    CleanBlackBoard();
    TurnOffLight();
}

  上面的代码没有使用委托,但是还是实现了需要完成的工作。很容易发现,开门、擦黑板、关灯,虽然他们的方法名称不同,但是它们具有相同的“形式”——它们都不获取参数,也都没有返回值(void),这正是委托可以发挥作用的时候。使用于这种形式匹配的一个委托。就可以引用任何工作的方法。我们可以声明如下的一个委托:

public delegate void DoSomeWorkDelegate();

 注意:

  • 声明委托时,要使用 delegate 关键字。
  • 委托定义了它能引用的方法的“形式”。你要指定返回类型(本例是void)、委托名称(DoSomeWorkDelegate)以及任何参数(本例无参数)。

  定义好委托之后,就可以创建它的一个实例,并使用 “+=”操作符,让这个实例引用一个相匹配的方法。代码如下:

public delegate void DoSomeWorkDelegate();
public DoSomeWorkDelegate doSomeWork;

doSomeWork+=OpenDoor;

  上例中的方法很简单,既没有返回值,又没有参数。目的只是了解在何种情况下使用委托。下面通过一个带参数的例子来说明继续说明如何使用委托。

  如何使用委托

  此处以听课为例,为了对比,同样先不使用委托,先上代码:

public void AttendClass(string name) {
    // 做某些额外的事情,比如初始化之类,此处略
    ChineseClass(name);
}
public void ChineseClass(string name) {
     //具体听语文课的逻辑
     ...  
}

  上面这段代码表示。AttendClass 表示听课,当我们传递代表学生姓名 name 参数,比如说“Jhon”,进去的时候,在这个方法中,将调用ChineseClass 方法,再次传递 Jhon 参数, 表示Jhon 参加了语文课。

  假设现在开设了数学课,我们需要添加新的方法:

public void MathClass(string name){
    //具体听数学课的逻辑    ...  
}

  这时候 AttendClass 也要修改,在此之前先定义一个枚举用作判断:

public enum Subject{
    Chinese,Math
}

public void AttendClass(string name, Subject sub){
    //做某些额外的事情,比如初始化之类,此处略
    swith(sub){
        case Subject.Chinese:           ChineseClass(name);
           break;
       case Subject.Math:
           MathClass(name);
           break;
    }
}

  OK,现在问题解决了,诚如前一个例子所说,假如现在又要增加英语课,体育课,就不得不反复修改枚举和 AttendClass 。可见程序的可拓展性很不好。

如前例,对于上课的方法,不论是什么课,它们都具有相同的“形式”,这样我们即可使用委托。

在考虑如何使用委托之前,我们先看看 AttendClass  的方法签名:

public void AttendClass(string name, Subject sub)

  我们仅看 string name,在这里,string 是参数类型,name 是参数变量,当我们给字符串那么赋值时,我们可以在方法体内对这个name进行其他操作.现在假如现在让 AttendClass() 方法接受一个参数变量,这个变量可以代表另一个方法,当给这个变量赋值为 ChineseClass 时,它代表 ChineseClass() 这个方法,当给它赋值为 MathClass 时,他代表MathClass() 这个方法。就是说让用一个参数来代方法。比如,把这个参数命名为,SubClass ,然后我们在方法体内,就像使用参数一样使用SubClass。由于 SubClass 代表着一个方法,它的使用方式应该和它被赋值的方法(比如 ChineseClass)是一样的,比如

SubClass(string name)

  按照这样的思路这样,AttendClass(),就应该是这个样子的:

public void AttendClass(string name,*** SubClass){
    SubClass(name);
}

  注意到 *** ,这个位置通常放置的应该是参数的类型,现在就出现了一个问题:这个代表着方法的SubClass参数应该是什么类型的?

  如果我说答案就是委托。它定义了 SubClass 方法的种类,也就是 SubClass 方法参数的类型。如同 string 决定了AttendClass() 这个方法的第一个参数的类型一样,委托决定 AttendClass 方法中的第二个参数的类型。

  本例中委托的定义如下:

public delegate void ClassDelegate(string name);

  现在再次改动 AttendClass 方法:

public void AttendClass(string name,ClassDelegate SubClass){
    SubClass(name);
}

  委托ClassDelegate出现的位置与 string 相同,string是一个类型,那么ClassDelegate 应该也是一个类型,或者叫类(Class)。但是委托的声明方式和类却完全不同。那么本例完整有关上课的类的代码如下:

public delegate void ClassDelegate(string name);
public class OnClass{
        //其它代码
        ...
        public void AttendClass(string name,ClassDelegate SubClass){
                SubClass(name);
        }

        public void ChineseClass(string name){
                ...
        }
        public void MathClass(string name){
                ...
        }
}

  由此可见,委托是一种类型。它定义了方法的类型,实际上就是把方法当做变量。(注意与指针的区别)

  那么我们如何使用它呢,代码如下:

private OnClass objOnClass;
objOnClass=new OnClass();
string name1="xiaoming";
string name2="小张";
objOnClass.AttendClass(name1,ChineseClass);
objOnClass.AttendClass(name2,MathClass);

  上面的代码表示 xiaoming 参加了语文课,小张参加了数学课。既然委托是一种类型。那么我们也可以以下面的方式来运用委托

ClassDelegate delegate1,delegate2;
delegate1=objOnClass.ChineseClass;
delegate2=objOnClass.MathClass;
string name1="xiaoming";
string name2="小张";
objOnClass.AttendClass(name1,delegate1);
objOnClass.AttendClass(name2,delegate2);

  还可以将多个方法付给同一个委托,下面的代码表示小张既参加了语文课,又参加了数学课

ClassDelegate delegate3;
delegate3=objOnClass.ChineseClass;
delegate3+=objOnClass.MathClass;
string name1="小张";
objOnCLass.AttendClass(name1,delegate3);

  可以看到,为委托绑定方法我们使用 重载了的 += 这个符号。如果将上面的代码中第一次绑定方法 delegate3=ChineseClass 改为 delegate3+=ChineseClass,将会出现“使用了未赋值的局部变量”的错误。我们可以像下面这样使用委托,给它初始化赋值

ClassDelegate delegate3=new ClassDelegate(objOnClass.ChineseClass);
string name1="xiaoming";
objOnClass.AttendClass(name1,delegate3);

  我们甚至可以不用AttendClass这个方法,像下面这样来使用委托

ClassDelegate delegate3=new ClassDelegate(objOnClass.ChineseClass);
string name1="xiaoming";
delegate3(name1);

  所以,可以将多个方法绑定到一个委托上面,调用的时候依次执行。

时间: 2024-10-25 05:25:55

学习和理解C#的委托的相关文章

SSH加密原理、RSA非对称加密算法学习与理解

首先声明一下,这里所说的SSH,并不是Java传统的三大框架,而是一种建立在应用层和传输层基础上的安全外壳协议,熟悉Linux的朋友经常使用到一 个SSH Secure Shell Cilent的工具,本文也是基于此工具加密原理的学习,在SSH的加密原理中,使用到了RSA非对称加密算法,本文也一并做了学习和了解. 非对称加密算法 在日常的工作生产中, 我们经常需要进行数据的通讯,开发人员经常需要对数据进行加解密操作,以保证数据的安全.数据的加密算法非为对称加密和非对称加密两种,常用的DES.三

JDK学习---深入理解java中的LinkedList

本文参考资料: 1.<大话数据结构> 2.http://blog.csdn.net/jzhf2012/article/details/8540543 3.http://blog.csdn.net/jzhf2012/article/details/8540410 4.http://www.cnblogs.com/ITtangtang/p/3948610.html 5.http://blog.csdn.net/zw0283/article/details/51132161 本来在分析完HashSe

一名工程师对于深度学习的理解-神经网络基础ANN

原文链接 序 读书期间对于深度学习也有涉及,不过只是皮毛,在这个数据和算法的时代,也需要更加贴近算法.于是从一名工程师角度出发,希望通过几篇文章,将深度学习基础记录下来,同时也是对于自己学习的总结和积累.总体思路是ANN-CNN-DNN,中间想起来有什么忘记的,也会加番. 神经网络概述 这是一张典型的人工神经网络的图,图中的节点称为神经元,图共分为三层,第一层为输入层,第二层为隐藏层,第三层为输出层.输入层接受外部世界的输入,具像化为图像的像素值,实体的特征值等,输出层概率预测结果,具像化为该图

对属性动画ObjectAnimator.ofObject方法的学习和理解

关于对属性动画 ObjectAnimator.ofObject(view, "position", new PointEvaluator(), pStart, pEnd); 方法的学习和理解,做个总结,也当做笔记记在这里,遗忘的时候以便查阅,也希望能帮助正在学习这块知识的同学. 这个方法的主要作用是根据一定的规则对目标对象的某个具体属性进行改变,从而使目标对象实现与该属性相关的动画效果. 参数的讲解: 第一个参数:动画的实施对象 第二个参数:关键词,在动画的实施对象中必须要有一个 &q

python基础知识的学习和理解

参考链接:https://github.com/yanhualei/about_python/tree/master/python_learning/python_base python基础知识笔记 Flask aiohttp的学习和理解 assert() asyncio的学习和理解 continue_break学习和理解 cprofile代码效率分析 datatime dict字典学习与理解 django_project eval() filter() gevent协程的学习和理解 http服

对英语语法定语从句学习的理解

学习英语语法,首先要了解英语有哪些句型? 从轮廓上大致知道英语的形,从而能够建立对英语的初步认识. 英语句子分为5中基本句型 1.主谓(i do)2.主谓宾(l like you) 3.主谓双宾(i buy you gifts) 4.主谓宾补(you make me happy) 5.主系表(l am a boy) 英语中都有哪些成分? 由形在到内部详细构造,主要有定语,同位语,插入语,状语,(其他不再多说) 定语的识别? 1.前置定语(忽略不计)2.后置定语 后置定语(1.形容词性短语 2.现

[express.js学习笔记]理解Router

(本文内容纯属个人理解,仅供学习探讨) 博主的工作用的是Java Web,私下对JavaScript很感兴趣,也就接触了Node.js,听过Node一般使用Express来搭建Web服务器,就找到了Express,开始阅读文档和例子. 发现官方文档API页面的导航列出了express的几个核心的类(对象): 1. express 2. Application 3. Request 4. Response 5. Router 其中,按照我的理解,express是一个Application对象的工厂

PHP面向对象三大特点学习(充分理解抽象、封装、继承、多态)

PHP面向对象三大特点学习 学习目标:充分理解抽象.封装.继承.多态 面象对向的三大特点:封装性.继承性.多态性 首先简单理解一下抽象:我们在前面定义一个类的时候,实际上就是把一类事物共有的属性和行为提取出来,形成一个物理模型(模版),这种研究问题的方法称为抽象 一.封装性 封装就是把抽取出来的数据和对数据的操作封装在一起,数据被保护在内部,程序的其他部分只有被授权的操作(方法)才能对数据进行操作. php提供了三种访问控制修饰符 public 表示全局,本类内部,类外部,子类都可以访问 pro

[学习笔记] 理解ASP.NET MVC的路由系统

引言 路由,正如其名,是决定消息经由何处被传递到何处的过程.也正如网络设备路由器Router一样,ASP.NET MVC框架处理请求URL的方式,同样依赖于一张预定义的路由表.以该路由表为转发依据,请求URL最终被传递给特定Controller的特定Action进行处理.而在相反的方向上,MVC框架的渲染器同样要利用这张路由表,生成最终的HTML页面并返回URL.所以,理解整个ASP.NET MVC的路由系统,有两个必须出现的关键元素:Controller与Action,有两个方向的操作:传入的