原文地址: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. css基本知识

    WANGJUN59451   css基本知识 1.CSS 简介 CSS 指层叠样式表 (Cascading Style Sheets),是一种用来表现 HTML 文档样式的语言,样式定义如何显示 HT ...

  2. Failed to run the WC DB work queue associated with 错误的解决

    转载自 http://blog.csdn.net/alan00000/article/details/44084455 svn checkout 代码是出现如标题的错误,提示我clean up ,cl ...

  3. BZOJ 2768 冠军调查(最小割)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2768 题意:给出一个无向图,每个点有一个值0或者1.现在重新设置每个点的值0或者1.设重 ...

  4. An Example of On-Error Trigger in Oracle Forms

    I wrote this trigger around 4 years ago to handle errors in an application based on Oracle Forms 6i. ...

  5. HDU 5723 Abandoned country(落后渣国)

    HDU 5723 Abandoned country(落后渣国) Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/65536 ...

  6. hdu 4163 Stock Prices 水

    #include<bits/stdc++.h> using namespace std; #define ll long long #define pi (4*atan(1.0)) #de ...

  7. read 判定用户输入的状态后运行相应的结果

    文件名: test26.sh #!/bin/bash # getting just one character of input read -n1 -p "Do you want to co ...

  8. Jquery动画方法 jquery.animate()

    目前在学习Oracle数据库,由于刚接触,学校让练习练习HTML内容,就想起了老师以前提起过的animate方法 animate是jquery的一个方法,这个方法主要功能是能实现比较平滑的动态效果,所 ...

  9. Nofollow

    今天整理一下SEO中经常用到的nofollow属性. nofollow它是HTML标签中的一个属性值,作用是告诉搜索引擎不要跟踪带有改属性值的链接, 用于指示搜索引擎不要追踪(即抓取)网页上的带有no ...

  10. c 函数调用产生的汇编指令和数据在内存情况(1)

    一直对函数调用的具体汇编指令和各种变量在内存的具体分配,一知半解.各种资料都很详细,但是不实践,不亲自查看下内存总不能笃定.那就自己做下. 两个目的: 一,函数和函数调用编译后的汇编指令基本样貌 二, ...