使用委派 (C# 程式設計手冊)Using Delegates (C# Programming Guide)

委派是可以安全封裝方法的類型,類似於 C 和 C++ 中的函式指標。A delegate is a type that safely encapsulates a method, similar to a function pointer in C and C++. 與 C 函式指標不同之處在於,委派為物件導向且類型安全,同時安全性較佳。Unlike C function pointers, delegates are object-oriented, type safe, and secure. 委派的類型由委派的名稱所定義。The type of a delegate is defined by the name of the delegate. 下列範例宣告名為 Del 的委派,其可封裝採用字串作為引數並傳回 void 的方法:The following example declares a delegate named Del that can encapsulate a method that takes a string as an argument and returns void:

public delegate void Del(string message);

通常透過提供委派將包裝的方法名稱,或使用匿名方法,來建構委派物件。A delegate object is normally constructed by providing the name of the method the delegate will wrap, or with an anonymous Method. 一旦對委派執行個體化之後,該委派即會將該委派的方法呼叫,傳遞至該方法。Once a delegate is instantiated, a method call made to the delegate will be passed by the delegate to that method. 由呼叫端傳遞至委派的參數,會傳遞至該方法,而從該方法傳回的值(如果有的話)會由該委派傳回至呼叫端。The parameters passed to the delegate by the caller are passed to the method, and the return value, if any, from the method is returned to the caller by the delegate. 這稱為叫用委派。This is known as invoking the delegate. 執行個體化的委派的叫用方法,就像其自身為包裝的方法一樣。An instantiated delegate can be invoked as if it were the wrapped method itself. 例如: For example:

// 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 types are derived from the Delegate class in the .NET Framework. 委派類型是密封的,不能作為其他類型的衍生來源,且不可能從 Delegate 衍生自訂類別。Delegate types are sealed—they cannot be derived from— and it is not possible to derive custom classes from Delegate. 因為執行個體化的委派是物件,所以它可以做為參數傳遞或指派給屬性。Because the instantiated delegate is an object, it can be passed as a parameter, or assigned to a property. 這可讓方法以參數方式接受委派,並於稍後呼叫委派。This allows a method to accept a delegate as a parameter, and call the delegate at some later time. 這稱為非同步回呼,是較長處理序完成時通知呼叫端的常用方法。This is known as an asynchronous callback, and is a common method of notifying a caller when a long process has completed. 以這種方式使用委派時,使用委派的程式碼不需要了解如何實作所用的方法。When a delegate is used in this fashion, the code using the delegate does not need any knowledge of the implementation of the method being used. 該功能類似於介面提供的封裝。The functionality is similar to the encapsulation interfaces provide.

回呼的另一種常見用法是定義自訂比較方法,並將該委派傳遞至排序方法。Another common use of callbacks is defining a custom comparison method and passing that delegate to a sort method. 它可讓呼叫端程式碼成為排序演算法的一部分。It allows the caller's code to become part of the sort algorithm. 下列的範例方法使用 Del 類型做為參數:The following example method uses the Del type as a parameter:

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

然後,您可以將上述所建立的委派傳遞至該方法:You can then pass the delegate created above to that method:

MethodWithCallback(1, 2, handler);

並且會在主控台中收到下列輸出:and receive the following output to the console:

The number is: 3

使用委派做為抽象概念,MethodWithCallback 不需要直接呼叫主控台 — 設計時不需要一直考慮主控台。Using the delegate as an abstraction, MethodWithCallback does not need to call the console directly—it does not have to be designed with a console in mind. MethodWithCallback 所做的只是準備一個字串,然後將該字串傳遞給另一個方法。What MethodWithCallback does is simply prepare a string and pass the string to another method. 這項功能十分強大,因為委派的方法可以使用任何數目的參數。This is especially powerful since a delegated method can use any number of parameters.

當委派建構為要包裝執行個體方法時,該委派會參考執行個體與方法。When a delegate is constructed to wrap an instance method, the delegate references both the instance and the method. 除了委派所包裝的方法之外,委派也不會知道執行個體的類型,因此委派可參考任何類型的物件,只要該物件上存在符合委派簽章的方法即可。A delegate has no knowledge of the instance type aside from the method it wraps, so a delegate can refer to any type of object as long as there is a method on that object that matches the delegate signature. 當委派建構為會包裝靜態方法時,它只會參考該方法。When a delegate is constructed to wrap a static method, it only references the method. 請考慮下列宣告:Consider the following declarations:

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

連同先前所示的靜態 DelegateMethod,我們現在有三種方法,可以由 Del 執行個體進行包裝。Along with the static DelegateMethod shown previously, we now have three methods that can be wrapped by a Del instance.

叫用委派時,可以呼叫一個以上的方法。A delegate can call more than one method when invoked. 這稱為多點傳送。This is referred to as multicasting. 若要將一個額外的方法加入委派的方法清單 (引動過程清單),只需使用加法或加法指派運算子 ('+' 或 '+ ='),相加兩個委派即可。To add an extra method to the delegate's list of methods—the invocation list—simply requires adding two delegates using the addition or addition assignment operators ('+' or '+='). 例如: For example:

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 在其引動過程清單中包含三種方法:Method1Method2DelegateMethodAt this point allMethodsDelegate contains three methods in its invocation list—Method1, Method2, and DelegateMethod. 原始的三個委派 d1d2d3 維持不變。The original three delegates, d1, d2, and d3, remain unchanged. 當叫用 allMethodsDelegate 時,會依序呼叫所有三個方法。When allMethodsDelegate is invoked, all three methods are called in order. 如果委派使用參考參數,則參考會依序傳入這三個方法中的每一個,而且任一方法所做的任何變更,下一個方法都看得到。If the delegate uses reference parameters, the reference is passed sequentially to each of the three methods in turn, and any changes by one method are visible to the next method. 當任一方法擲回未在該方法內攔截到例外狀況時,該例外狀況會傳遞至委派的呼叫端,且不會呼叫引動過程清單中的任何後續方法。When any of the methods throws an exception that is not caught within the method, that exception is passed to the caller of the delegate and no subsequent methods in the invocation list are called. 如果委派具有傳回值和 (或) 輸出參數,則它會傳回所叫用之最後一個方法的傳回值與參數。If the delegate has a return value and/or out parameters, it returns the return value and parameters of the last method invoked. 若要移除引動過程清單中的方法,請使用遞減或遞減指派運算子 ('-' 或 '-= ')。To remove a method from the invocation list, use the decrement or decrement assignment operator ('-' or '-='). 例如: For example:

//remove Method1
allMethodsDelegate -= d1;

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

因為委派類型衍生自 System.Delegate,所以可以在委派上呼叫該類別所定義的方法和屬性。Because delegate types are derived from System.Delegate, the methods and properties defined by that class can be called on the delegate. 例如,若要求解委派引動過程清單中方法的數目,可以撰寫如下:For example, to find the number of methods in a delegate's invocation list, you may write:

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

其委派引動過程清單中有一個以上方法的委派,衍生自 MulticastDelegate,即 System.Delegate 的子類別。Delegates with more than one method in their invocation list derive from MulticastDelegate, which is a subclass of System.Delegate. 上述程式碼可以在任一情況下運作,因為這兩個類別都支援 GetInvocationListThe above code works in either case because both classes support GetInvocationList.

多點傳送委派常用於事件處理。Multicast delegates are used extensively in event handling. 事件來源物件會將事件通知傳送給已註冊希望收到該事件的收件者物件。Event source objects send event notifications to recipient objects that have registered to receive that event. 若要註冊接收事件,收件者會建立旨在處理事件的方法,然後建立該方法的委派,並將該委派傳遞至事件來源。To register for an event, the recipient creates a method designed to handle the event, then creates a delegate for that method and passes the delegate to the event source. 在發生事件時,來源會呼叫委派。The source calls the delegate when the event occurs. 接著,委派會呼叫收件者的事件處理方法,傳遞事件資料。The delegate then calls the event handling method on the recipient, delivering the event data. 指定的事件之委派類型,由事件來源定義。The delegate type for a given event is defined by the event source. 如需詳細資訊,請參閱事件For more, see Events.

比較兩個在編譯時間所指定的不同類型之委派,會導致編譯錯誤。Comparing delegates of two different types assigned at compile-time will result in a compilation error. 如果委派執行個體是靜態類型的 System.Delegate,則允許比較,但會在執行階段傳回 false。If the delegate instances are statically of the type System.Delegate, then the comparison is allowed, but will return false at run time. 例如: For example:

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);
}

請參閱See Also

C# 程式設計指南C# Programming Guide
委派Delegates
在委派中使用變異數Using Variance in Delegates
委派中的變異數Variance in Delegates
針對 Func 與 Action 泛型委派使用變異數Using Variance for Func and Action Generic Delegates
事件Events