1委托是一种安全地封装方法的类型,它与 C 和 C++ 中的函数指针类似。 与 C 中的函数指针不同,委托是面向对象的、类型安全的和保险的。 委托的类型由委托的名称定义。
声明了一个名为 Del 的委托,该委托可以封装一个采用字符串作为参数并返回 void 的方法。构造委托对象时,通常提供委托将包装的方法的名称或使用匿名方法。 实例化委托后,委托将把对它进行的方法调用传递给方法。 调用方传递给委托的参数被传递给方法,来自方法的返回值(如果有)由委托返回给调用方。 这被称为调用委托。 可以将一个实例化的委托视为被包装的方法本身来调用该委托。 例如:
// 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);
完整例子如下:
using System; using System.Collections.Generic; using System.Text; using ConsoleApplication1;
namespace ConsoleApplication1 { public class SampleEventArgs { public delegate void Del(string message);//定义委托 public static void DelegateMethod(string message)//定义和委托具有相同签名的方法 { Console.WriteLine(message); Console.ReadKey(); } public static void MethodWithCallback(int param1, int param2, Del callback) { callback("The number is: " + (param1 + param2).ToString());//调用委托的引用
} public static void Main(string[] args) { Del handler = DelegateMethod;//实例化委托 handler("Hello World");//调用委托
MethodWithCallback(1, 2, handler);//传递委托的实例
} } }
在控制台中将收到下面的输出:
The number is: 3
将委托构造为包装实例方法时,该委托将同时引用实例和方法。 除了它所包装的方法外,委托不了解实例类型,所以只要任意类型的对象中具有与委托签名相匹配的方法,委托就可以引用该对象。 将委托构造为包装静态方法时,它只引用方法
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;
在其调用列表中包含三个方法
原来的三个委托 d1、d2 和 d3 保持不变。
调用allMethodsDelegate 时,将按顺序调用所有这三个方法。
如果委托使用引用参数,则引用将依次传递给三个方法中的每个方法,由一个方法引起的更改对下一个方法是可见的。 如果任一方法引发了异常,而在该方法内未捕获该异常,则该异常将传递给委托的调用方,并且不再对调用列表中后面的方法进行调用。 如果委托具有返回值和/或输出参数,它将返回最后调用的方法的返回值和参数。 若要从调用列表中移除方法,请使用减法运算符或减法赋值运算符(“-”或“-=”)。
由于委托类型派生自 System.Delegate,所以可在委托上调用该类定义的方法和属性。 例如,为了找出委托的调用列表中的方法数,
int invocationCount = d1.GetInvocationList().GetLength(0);