原文地址:https://msdn.microsoft.com/zh-cn/library/ms173172.aspx

委托是安全封装方法的类型,类似于 C 和 C++ 中的函数指针。  与 C 函数指针不同的是,委托是面向对象的、类型安全的和可靠的。  委托的类型由委托的名称确定。  以下示例声明名为 Del 的委托,该委托可以封装采用字符串作为参数并返回 void 的方法:

 
public delegate void Del(string message);

委托对象通常通过提供委托将封装的方法的名称或使用匿名方法构造。  对委托进行实例化后,委托会将对其进行的方法调用传递到该方法。  调用方传递到委托的参数将传递到该方法,并且委托会将方法的返回值(如果有)返回到调用方。  这被称为调用委托。  实例化的委托可以按封装的方法本身进行调用。  例如:

 
  // Create a method for a delegate.
public static void DelegateMethod(string message)
{
System.Console.WriteLine(message);
}
 
  // Instantiate the delegate.
Del handler = DelegateMethod; // Call the delegate.
handler("Hello World");

委托类型派生自 .NET Framework 中的 Delegate 类。  委托类型是封装的,它们不能派生出其他类,也不能从 Delegate 派生出自定义类。  由于实例化的委托是一个对象,因此可以作为参数传递或分配给一个属性。  这允许方法作为参数接受委托并在稍后调用委托。  这被称为异步回调,是在长进程完成时通知调用方的常用方法。  当以这种方式使用委托时,使用委托的代码不需要知道要使用的实现方法。  功能类似于封装接口提供的功能。

回调的另一个常见用途是定义自定义比较方法并将该委托传递到短方法。  它允许调用方的代码成为排序算法的一部分。  以下示例方法使用 Del类型作为参数:

 
public void MethodWithCallback(int param1, int param2, Del callback)
{
callback("The number is: " + (param1 + param2).ToString());
}

然后,你可以将上面创建的委托传递到该方法:

 
MethodWithCallback(1, 2, handler);

并将以下输出接收到控制台:

The number is: 3

以抽象方式使用委托时,MethodWithCallback 不需要直接调用控制台,记住,其不必设计为具有控制台。   MethodWithCallback 的作用是简单准备字符串并将字符串传递到其他方法。  由于委托的方法可以使用任意数量的参数,此功能特别强大。

当委托构造为封装实例方法时,委托将同时引用实例和方法。  委托不知道除其所封装方法以外的实例类型,因此委托可以引用任何类型的对象,只要该对象上有与委托签名匹配的方法。  当委托构造为封装静态方法时,委托仅引用方法。  请考虑以下声明:

 
public class MethodClass
{
public void Method1(string message) { }
public void Method2(string message) { }
}

加上之前显示的静态 DelegateMethod,我们现在已有三个 Del 实例可以封装的方法。

调用时,委托可以调用多个方法。  这被称为多播。  若要向委托的方法列表(调用列表)添加其他方法,只需使用加法运算符或加法赋值运算符(“+”或“+=”)添加两个委托。  例如:

 
MethodClass obj = new MethodClass();
Del d1 = obj.Method1;
Del d2 = obj.Method2;
Del d3 = DelegateMethod; //Both types of assignment are valid.
Del allMethodsDelegate = d1 + d2;
allMethodsDelegate += d3;

此时,allMethodsDelegate 的调用列表中包含三个方法,分别为 Method1、Method2 和 DelegateMethod。  原有的三个委托(d1、d2 和d3)保持不变。  调用 allMethodsDelegate 时,将按顺序调用所有三个方法。  如果委托使用引用参数,引用将按相反的顺序传递到所有这三个方法,并且一种方法进行的任何更改都将在另一种方法上见到。  当方法引发未在方法内捕获到的异常时,该异常将传递到委托的调用方,并且不会调用调用列表中的后续方法。  如果委托具有返回值和/或输出参数,它将返回上次调用方法的返回值和参数。  若要删除调用列表中的方法,请使用减法运算符或减法赋值运算符(“+”或“+=”)。  例如:

 
//remove Method1
allMethodsDelegate -= d1; // copy AllMethodsDelegate while removing d2
Del oneMethodDelegate = allMethodsDelegate - d2;

由于委托类型派生自 System.Delegate,因此可以在委托上调用该类定义的方法和属性。  例如,若要查询委托调用列表中方法的数量,你可以编写:

 
int invocationCount = d1.GetInvocationList().GetLength(0);

调用列表中具有多个方法的委托派生自 MulticastDelegate,该类属于 System.Delegate 的子类。  由于这两个类都支持 GetInvocationList,因此在其他情况下,上述代码也将产生作用。

多播委托广泛用于事件处理中。  事件源对象将事件通知发送到已注册接收该事件的接收方对象。  若要注册一个事件,接收方需要创建用于处理该事件的方法,然后为该方法创建委托并将委托传递到事件源。  事件发生时,源调用委托。  然后,委托将对接收方调用事件处理方法,从而提供事件数据。  给定事件的委托类型由事件源确定。  有关详细信息,请参阅事件(C# 编程指南)

在编译时比较分配的两个不同类型的委托将导致编译错误。  如果委托实例是静态的 System.Delegate 类型,则允许比较,但在运行时将返回 false。  例如:

 
delegate void Delegate1();
delegate void Delegate2(); static void method(Delegate1 d, Delegate2 e, System.Delegate f)
{
// Compile-time error.
//Console.WriteLine(d == e); // OK at compile-time. False if the run-time type of f
// is not the same as that of d.
System.Console.WriteLine(d == f);
}

使用委托(C# 编程指南)的更多相关文章

  1. Lambda 表达式(C# 编程指南) 微软microsoft官方说明

    Visual Studio 2013 其他版本 Lambda 表达式是一种可用于创建委托或表达式目录树类型的匿名函数. 通过使用 lambda 表达式,可以写入可作为参数传递或作为函数调用值返回的本地 ...

  2. C#泛型(C#_编程指南)CSDN学习整理笔记

    1.1. 泛型概述 2.0版C#语言和公共语言运行时(CLR)中增加了泛型.泛型将类型参数的概念引入.NETFramework,类型参数使得设计如下类和方法成为可能:这些类和方法将一个或多个类型的指定 ...

  3. 转载c#泛型 类型参数的约束(c#编程指南)

    在定义泛型类时,可以对客户端代码能够在实例化类时用于类型参数的类型种类施加限制.如果客户端代码尝试使用某个约束所不允许的类型来实例化类,则会产生编译时错误.这些限制称为约束.约束是使用 where 上 ...

  4. 编程基础-msdn编程指南笔记

    此博仅为笔记,摘自msdn编程指南文档,链接地址:http://msdn.microsoft.com/zh-cn/library/67ef8sbd.aspx 注释:// 单行注释 /* 多行注释*/ ...

  5. (zz)Lambda 表达式(C# 编程指南)

    https://msdn.microsoft.com/zh-cn/library/bb397687.aspx Lambda 表达式是一种可用于创建委托或表达式目录树类型的匿名函数.通过使用 lambd ...

  6. 访问修饰符(C# 编程指南)

    所有类型和类型成员都具有可访问性级别,该级别可以控制是否可以从你的程序集或其他程序集中的其他代码中使用它们. 可以使用以下访问修饰符在进行声明时指定类型或成员的可访问性: public同一程序集中的任 ...

  7. C# 编程指南

    此部分详细介绍了 C# 语言主要功能,以及通过 .NET Framework 可以在 C# 中使用的功能. 阅读此部分的大部分内容的前提是,你已对 C# 和一般编程概念有一定的了解. 如果完全没有接触 ...

  8. vertx 异步编程指南 step8-使用RxJava进行反应式编程

    vertx 异步编程指南 step8-使用RxJava进行反应式编程 2018-04-23 13:15:32 zyydecsdn 阅读数 1212  收藏 更多 分类专栏: vertx   到目前为止 ...

  9. OpenGL编程指南(第七版)

    OpenGL编程指南(第七版) 转自:http://blog.csdn.net/w540982016044/article/details/21287645 在接触OpenGL中,配置显得相当麻烦,特 ...

随机推荐

  1. iOS日常工作之常用宏定义大全

    前言: 在工作中, 很多小伙伴都会在PCH文件定义一些常用的宏,但是又怕写这些简单的宏浪费时间,又有时候忘记怎么定义了怎么办?本人在工作中也是如此.所以在这里给大家分享一些常用的宏定义,喜欢的小伙伴可 ...

  2. 【转载】跟着9张思维导图学习JavaScript

    原文:跟着9张思维导图学习JavaScript 学习的道路就是要不断的总结归纳,好记性不如烂笔头,so,下面将 po 出我收集的 9 张 JavaScript相关的思维导图(非原创). 思维导图小ti ...

  3. git生成SSH key

    使用https:// 提交GitHub上的私有项目时,需要每次都输入帐号和密码,比较麻烦. 比如我自己的笔记本,在push的时候我可不想每次都输入这些. 那就使用SSH吧,这个需要在GitHub的帐号 ...

  4. 【CSS】最全的CSS浏览器兼容问题

    CSS对浏览器的兼容性有时让人很头疼,或许当你了解当中的技巧跟原理,就会觉得也不是难事,从网上收集了IE7,6与Fireofx的兼容性处理方法并 整理了一下.对于web2.0的过度,请尽量用xhtml ...

  5. JAVA排序--[快速排序]

    package com.array; public class Sort_Quick { /* * 项目名称:快速排序 ; * 项目要求:用JAVA对数组进行排序,并运用快速排序算法; * 作者:Se ...

  6. hdu 0-1背包

    题目地址http://acm.hdu.edu.cn/showproblem.php?pid=2602 #include <stdio.h> #include <string.h> ...

  7. 关于gitlab的一个问题解决

    这两天折腾一个关于gitlab的问题,搞得比较焦头烂额.不过经过折腾,最终还是成功了. 当面对着一个问题,并且看到还没被解决的时候,感觉很不舒服: 努力折腾之后,解决之后,也会身体轻松.或许工程师天生 ...

  8. ubuntu安装jdk-6u45-linux-x64.bin___ZC_20160423

    for : Android4.4源码编译 环境 : ubuntu12.04_desktop_amd64 1. 1.1.jdk-6u45-linux-x64.bin 放置于 /home 1.2.命令&q ...

  9. [转载] C++ 多线程编程总结

    原文: http://www.cnblogs.com/zhiranok/archive/2012/05/13/cpp_multi_thread.html 在开发C++程序时,一般在吞吐量.并发.实时性 ...

  10. Python学习笔记6-字典

    定义 使用键值对, >>> person = {"name":"keven","age":15,"gender& ...