=============================版权申明===============================

  任何人都可以转载,但请注明转载地址和作者“天轰穿”,因为下面这是我正在写的 c# 这本书中的节选内容。

整本书都是这个风格,朋友们有啥期待尽管提。

===========================版权申明结束,内容开始======================

6.3.1 C#中定义委托

在C#中使用一个类时,分两个阶段。首先需要定义这个类,即告诉编译器这个类由什么字段和方法组成。然后(除非只使用静态方法)实例化类的一个对象。使用委托时,也需要经过这两个步骤。首先定义要使用的委托,对于委托,定义它就是告诉编译器这种类型的委托代表了哪种类型的方法,然后创建该委托的一个或多个实例。编译器在后台将创建表示该委托的一个类。

定义委托的语法如下:

访问修饰符 delegate 返回值类型 委托名称(参数1, 参数1, 参数n…);

//------------例如--------------------

//不返回值,也没有参数的委托类型BB

public delegate void BB();

//返回string类型值,需要两个参数的委托类型AA

public delegate string AA(int a, string b);

委托的一个要点是它们的类型安全性非常高。在定义委托时,必须给出它所代表的方法签名和返回类型等全部细节。

如果觉得不好理解可以把委托当作给方法签名和返回类型指定名称。因为其语法类似于方法的定义,但没有方法体,定义的前面要加上关键字delegate。因为定义委托基本上是定义一个新类,所以可以在定义类的任何地方定义委托,既可以在另一个类的内部定义,也可以在任何类的外部定义,还可以在命名空间中把委托定义为顶层对象。根据定义的可见性,可以在委托定义上添加一般的访问修饰符:public、private、protected等:

实际上,“定义一个委托”是指“定义一个新类”。委托实现为派生自基类System. Multicast Delegate的类,System.MulticastDelegate又派生自基类System.Delegate。C#编译器知道这个类,会使用其委托语法,因此我们不需要了解这个类的具体执行情况,这是C#与基类共同合作,使编程更易完成的另一个示例。

定义好委托后,就可以创建它的一个实例,以存储特定方法的细节。

6.3.2 使用委托

委托是一种安全地封装方法的类型,它与 C 和 C++ 中的函数指针类似。与 C 中的函数指针不同,委托是面向对象的、类型安全的和保险的。委托的类型由委托的名称定义。下面的示例声明了一个名为 Del 的委托:

//声明了一个名为 Del 的委托,该委托可以封装一个采用字符串作为参数并返回 void 的方法。

public delegate void Del(string message);

构造委托对象时,通常提供委托将包装的方法的名称或使用匿名方法。实例化委托后,委托将把对它进行的方法调用传递给方法。调用方传递给委托的参数被传递给方法,来自方法的返回值(如果有)由委托返回给调用方。这被称为调用委托。可以将一个实例化的委托视为被包装的方法本身来调用该委托。例如:

using System;

namespace _63demo

{

//声明了一个名为 Del 的委托,该委托可以封装一个采用字符串作为参数并返回 void 的方法。

public delegate void Del(string message);

class Program

{

//新增一个方法,

public static void DelegateMethod(string message)

{

System.Console.WriteLine(message);

}

static void Main()

{

//为新申明的委托实例的委托对象为DelegateMethod,这句有点绕,这样理解

//既然是委托,那么肯定会有个最终执行者,反正不要期望委托本身干事

Del handler = DelegateMethod;

//使用委托,其实等同于直接使用DelegateMethod方法,因为最终是委托给这个方法的

handler("调用委托来了");

Console.ReadLine();

}

}

}

小天:没觉得有什么意思,要调用方法DelegateMethod,我直接调用就行了,好像犯不着绕一大圈。你看我要显示一个消息,我首先去找到一个中介所(委托),然后将要显示的消息交给中介所,然后他来帮我显示。

老田:现在社会上形形色色的中介机构那么多,要知道存在即是合理。就上面实例来说,显示一个消息当然没有必要找中介。但如果你要做的是很复杂的事呢?下面我们再来将委托进行二次外包。有点像你喜欢上某个美女,但是你不好意思跟她说。于是你找了个做媒的人,然后你将你要给这个女孩子的定情信物和媒人一起给了一个专业说媒的方法(可以理解这个方法就是一个说媒的场景)。还是继续使用上面已经有的代码,只是新增一个方法和相应的调用语句,具体执行代码如下:

/// <summary>

/// //新增一个方法,就是说媒的场景

/// </summary>

/// <param name="param1">参数(男孩信息)1</param>

/// <param name="param2">参数(所给信物)2</param>

/// <param name="callback">媒婆</param>

public static void MethodWithCallback(string param1, string param2, Del callback)

{

//多个字符串相加最好用这种方式,性能更高

StringBuilder say = new StringBuilder();

say.Append("有个臭P的家伙喜欢你,他的信息如下:/n");

say.Append(param1);

say.Append("/n他还送上");

say.Append(param2);

say.Append("作为定情信物");

callback(say.ToString());

}

static void Main()

{

Del handler = DelegateMethod;

string info = "名叫小天,年方二八,除了没钱和长得太帅外基本没有缺点"; //个人信息

string gift = "天轰穿趣味编程系列图书";                               //信物

MethodWithCallback(info, gift, handler);         //将委托也作为参数传递

Console.ReadLine();

}

执行后效果如图6-4

图6-4

小天:为什么上面的方法都是静态(static)的呢?

老田:因为这是个控制台应用程序,而控制台应用程序的入口方法Main是static的。要使这些方法能够被Main调用,当然只能是静态,这个都不清楚的话赶紧回去复习类设计那一章。

另外,将委托构造为包装实例方法时,该委托将同时引用实例和方法。除了它所包装的方法外,委托不了解实例类型,所以只要任意类型的对象中具有与委托签名相匹配的方法,委托就可以引用该对象。将委托构造为包装静态方法时,它只引用方法。比如下面示例,我们新增一个类,里面增加两个方法,然后分别交给委托:

//新增的类,里面有三个方法

public class MethodClass

{

public void Method1(string msg)

{

Console.WriteLine("第一个方法的结果是:"+msg);

}

public void Method2(string msg)

{

Console.WriteLine("第二个方法的结果是:"+msg);

}

}

//在Main函数中使用

static void Main()

{

MethodClass mc = new MethodClass(); //实例化一个被调用类的实例

//注意下面三个关联的方法,他们的类实例是不同的,但是它们的方法签名是一样的

Del handler1 = mc.Method1;

Del handler2 = mc.Method2;

//下面这个方法是前面示例使用的方法

Del handler = DelegateMethod;

//调用委托

handler1("小天");

handler2("老田");

Console.ReadLine();

}

小天:也就是说,委托只管被委托的方法的返回类型和参数列表是符合的就可以了,并不太在意具体的类实例。难道这就是传说的“英雄不问出生”?

老田:另外,我们还可以将上面三个委托来个批发,现在将上例中三个委托实例handler1,handler2,handler3来个打包执行,代码如下:

//在Main函数中使用

static void Main()

{

MethodClass mc = new MethodClass(); //实例化一个被调用类的实例

Del handler1 = mc.Method1;

Del handler2 = mc.Method2;

Del handler3 = DelegateMethod;

Del handler4 = handler1 + handler2; //第一种打包方法

handler4 += handler3;               //将handler3添加到handler4的执行序列中

//调用委托

handler4("打包执行");

}

6.3.3 多播委托

此时,handler4在其调用列表中包含三个方法 -- Method1、Method2 和 DelegateMethod。原来的三个委托 handler1、handler2和 handler3 保持不变。调用 allMethodsDelegate 时,将按顺序调用所有这三个方法。如果委托使用引用参数,则引用将依次传递给三个方法中的每个方法,由一个方法引起的更改对下一个方法是可见的。如果任一方法引发了异常,而在该方法内未捕获该异常,则该异常将传递给委托的调用方,并且不再对调用列表中后面的方法进行调用。如果委托具有返回值和/或输出参数,它将返回最后调用的方法的返回值和参数。若要从调用列表中移除方法,可以使用减法运算符或减法赋值运算符(“-”或“-=”)。例如:

// 从handler4中移除handler3

handler4 -= handler3;

//新申明一个handler5,等于handler4移除handler2后的结果

Del handler5 = handler4 - handler2;

小天:这个就是前面实例中讲到的多播委托吧。这个我知道了,不过我发现这么加加减减的,搞到最后,有什么办法知道到底委托序列中有多少个方法不?

老田:由于委托类型派生自 System.Delegate,所以可在委托上调用该类定义的方法和属性。例如,为了找出委托的调用列表中的方法数,您可以编写下面的代码:

//获取多路广播(简称“多播”)委托中的方法数量

handler5.GetInvocationList().GetLength(0);

多路广播委托广泛用于事件处理中。事件源对象向已注册接收该事件的接收方对象发送事件通知。为了为事件注册,接收方创建了旨在处理事件的方法,然后为该方法创建委托并将该委托传递给事件源。事件发生时,源将调用委托。然后,委托调用接收方的事件处理方法并传送事件数据。给定事件的委托类型由事件源定义。

小天:能够对多播委托实例进行遍历不?

老田:可以的,如下例:

static void Main()

{

MethodClass mc = new MethodClass();     //被调用方法的类实例

Del d1, d2, d3, d4;                     //申明多个委托实例

d1 = mc.Method1;

d2 = mc.Method2;

d3 = DelegateMethod;

d4 = d1 + d2 + d3;                      //d4等于前面三个相加

//申明一个委托类型的数组,将d4中的调用列表作为值给它

Delegate[] delegates = d4.GetInvocationList();

//申明一个变量i作为计数器

int i = 0;

foreach (Del d in delegates)

{

i++;        //i递加

d("我是方法 "+i.ToString());    //调用当前委托

}

}

执行后效果如图6-5

图6-5

对于多播委托的更多操作我就不一一介绍了,你自己结合动态帮助去尝试吧。

==

委托的定义和使用入门-天轰穿相关推荐

  1. [分享]天轰穿VS2005视频教程

    谈到学习,虽然有很多很多人有自己一套的自学方法. 但有时候,有个好的老师来教,一个好的拍档一同促进也是十分重要的. 就在一个星期前我偶然在Google上点入了天轰穿的blog 发现里面的VS2005视 ...

  2. C#委托的定义 以及使用方式详解,更简单的理解委托。

    委托的声明及定义: 委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得 ...

  3. mybatis-day01-自定义框架-基础入门

    目录 一.今日内容 二.框架的介绍 1.什么是框架 2.框架能解决什么问题 3.三层架构中常用的框架 三.mybatis框架的介绍 1.jdbc中的代码 创建数据库: 新建maven工程,导入juni ...

  4. html类名定义规则_HTML入门笔记1

    HTML 是谁发明的? Tim Berners-Lee HTML起手式: HTML起手式 <!DOCTYPE html> <html lang="zh-CN"&g ...

  5. 天轰穿典型多层架构留言本项目实战免费下载

    本课程共九讲,建议学习时间(至少)20 小时以上 http://218.63.168.91/thc2008.rar 下面给大家讲讲本课程的一些特点. 1.幽默,嘿嘿,我还是尽量的见缝插针的填充一些幽默 ...

  6. C#入门面向对象编程(委托的使用)

    委托的概念 一.了解委托(delegate) 1.委托是一种全新的面向对象语言特性,运行在.NET平台 2.基于委托,开发事件驱动程序变得非常简单 3.使用委托可以大大简化多线程的难度 二.理解委托 ...

  7. RhinoMock入门(4)——次序和委托

    (一)次序(Ordered) 在rhinomock中,可以按次序调用方法.默认条件下,方法调用没有顺序.如果按次序录制,那么在调用方法时必须按录制时相同的次序进行. 请看: public interf ...

  8. 委托定义(delegate)

    委托定义: 委托(delegate)类型和类相似,也是一种引用类型,有委托类型定义委托对象(简称委托),委托与C/C++中的函数指针相似,不同的是,委托是面向对象的.类型安全的和保险的.一旦为委托分配 ...

  9. 【转】C#中的线程 入门

    Keywords:C# 线程 Source:http://www.albahari.com/threading/ Author: Joe Albahari Translator: Swanky Wu ...

  10. C#中的线程(一)入门

    文章系参考转载,英文原文网址请参考:http://www.albahari.com/threading/ 作者 Joseph Albahari,  翻译 Swanky Wu 中文翻译作者把原文放在了& ...

最新文章

  1. aac文件损坏修复软件_Mac不能安装非信任应用的解决方法 MAC软件安装必读 打不开身份不明的开发者?文件已损坏?...
  2. SAP Batch Derivation功能初探之二
  3. 观察者模式定义了一种一对多的对象关系,当一个对象改变时,此对象对应的监控对象跟着改变!!!...
  4. redis 持久化详解 RDB和AOF 优缺点
  5. Vue项目中一些常见的文件名及作用
  6. 不成为编程天才的5种贡献方式
  7. 支付宝上线长辈模式: 字体图标加大 去除了营销推送
  8. JavaScript == 和 ===
  9. php如何接受用户邮箱发送信息,怎么将用户购物车的产品发送到邮箱
  10. android xml设置roboto字体,Android设置Roboto字体用粗体,斜体,常规,…(类似于自定义字体系列)...
  11. github 仓库中文名_github仓库的使用
  12. 小程序or网页前端CSS选择器
  13. php 没有读取权限能不能复制,“需要提供管理员权限才能复制此文件夹”怎么办...
  14. aws api gateway 使用阿里云的域名访问
  15. EFcore Find和single的区别
  16. mysql 内存大_MySQL数据库之MySQL大内存配置方案
  17. SAP:在互联网时代帮助企业夺回数据
  18. 小梅哥FPGA学习笔记——串口发送模块
  19. PyQt5——显示图片
  20. IIS设置HTTP 响应标头控制文件下载

热门文章

  1. 【Web漏洞探索】跨站请求伪造漏洞
  2. Verilog中的按键消抖
  3. cuda 10.1 下载
  4. python考勤系统_使用Djang的考勤系统
  5. 合批/批量渲染 (Batch)、实例化Instancing
  6. autocad2014点击保存闪退_autocad2014启动闪退 AutoCAD启动时闪退怎么办
  7. HTML分页插件功能实现
  8. java中递归遍历文件夹下所有文件
  9. matlab图例只显示文字不显示线条
  10. 罗辑思维:怎么样成为一个高手 文字版