委托+多播委托
委托是一种安全封装方法的类型,类似于 C 和 C++ 中的函数指针。与 C 函数指针不同,委托是面向对象的、类型安全的。委托的类型由委托的名称定义。下面的示例声明一个名为的委托,该委托可以封装将字符串作为参数并返回 void 的方法:
public delegate void Del(string message);
委托对象通常通过提供委托将包装的方法的名称或使用 lambda 表达式来构造。实例化委托后,委托将对委托进行的方法调用传递给该方法。调用方传递给委托的参数将传递给该方法,并且委托将方法的返回值(如果有)返回给调用方。这称为调用委托。可以调用实例化的委托,就好像它是包装的方法本身一样。例如:
// Create a method for a delegate. public static void DelegateMethod(string message) { Console.WriteLine(message); } // Instantiate the delegate. Del handler = DelegateMethod; // Call the delegate. handler("Hello World");
回调的另一个常见用途是定义自定义比较方法并将该委托传递给排序方法。它允许调用方的代码成为排序算法的一部分。以下示例方法使用该类型作为参数:Del
public static void MethodWithCallback(int param1, int param2, Del callback) { callback("The number is: " + (param1 + param2).ToString()); } MethodWithCallback(1, 2, handler); 输出 The number is: 3
一个委托在调用时可以调用多个方法。这称为多播。若要将额外的方法添加到委托的方法列表(调用列表),只需使用添加或添加赋值运算符(“+”或“+=”)添加两个委托。例如:
public class MethodClass { public void Method1(string message) { } public void Method2(string message) { } } var 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;
委托对象的一个有用属性是,可以使用运算符将多个对象分配给一个委托实例。多播委托包含已分配委托的列表。调用多播委托时,它会按顺序调用列表中的委托。只能组合相同类型的委托。
using System; // Define a custom delegate that has a string parameter and returns void. delegate void CustomDel(string s); class TestClass { // Define two methods that have the same signature as CustomDel. static void Hello(string s) { Console.WriteLine($" Hello, {s}!"); } static void Goodbye(string s) { Console.WriteLine($" Goodbye, {s}!"); } static void Main() { // Declare instances of the custom delegate. CustomDel hiDel, byeDel, multiDel, multiMinusHiDel; // In this example, you can omit the custom delegate if you // want to and use Action<string> instead. //Action<string> hiDel, byeDel, multiDel, multiMinusHiDel; // Initialize the delegate object hiDel that references the // method Hello. hiDel = Hello; // Initialize the delegate object byeDel that references the // method Goodbye. byeDel = Goodbye; // The two delegates, hiDel and byeDel, are combined to // form multiDel. multiDel = hiDel + byeDel; // Remove hiDel from the multicast delegate, leaving byeDel, // which calls only the method Goodbye. multiMinusHiDel = multiDel - hiDel; Console.WriteLine("Invoking delegate hiDel:"); hiDel("A"); Console.WriteLine("Invoking delegate byeDel:"); byeDel("B"); Console.WriteLine("Invoking delegate multiDel:"); multiDel("C"); Console.WriteLine("Invoking delegate multiMinusHiDel:"); multiMinusHiDel("D"); } } /* Output: Invoking delegate hiDel: Hello, A! Invoking delegate byeDel: Goodbye, B! Invoking delegate multiDel: Hello, C! Goodbye, C! Invoking delegate multiMinusHiDel: Goodbye, D! */
要查找委托调用列表中的方法数量,您可以编写:System.Delegate
int invocationCount = d1.GetInvocationList().GetLength(0);
多播委托广泛用于事件处理。事件源对象将事件通知发送到已注册接收该事件的收件人对象。若要注册事件,收件人创建一个旨在处理事件的方法,然后为该方法创建一个委托,并将委托传递给事件源。事件发生时,源调用委托。然后,委托在收件人上调用事件处理方法,传递事件数据。给定事件的委托类型由事件源定义。有关详细信息,请参阅事件。
比较在编译时分配的两个不同类型的委托将导致编译错误。如果委托实例是静态类型的,则允许比较,但在运行时将返回 false。例如:System.Delegate
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. Console.WriteLine(d == f); }