共用方式為


使用委派 (C# 程式設計指南)

委派是可安全地封裝方法的類型,類似於 C 和 C++中的函式指標。 與 C 函式指標不同,委派是物件導向的、類型安全且具備安全性的。 下列範例會宣告名為 Callback 的委派,該委派可以封裝採用 字串 作為自變數並傳回 void 的方法:

public delegate void Callback(string message);

委派物件通常是藉由提供方法名稱或使用 Lambda 運算式來生成。 以這種方式具現化后,即可叫用委派。 呼叫委託時會執行附加至該委託實例的方法。 呼叫者傳遞給委派的參數會被傳遞至該方法。 委派傳回方法的傳回值(如果有的話)。 例如:

// Create a method for a delegate.
public static void DelegateMethod(string message)
{
    Console.WriteLine(message);
}
// Instantiate the delegate.
Callback handler = DelegateMethod;

// Call the delegate.
handler("Hello World");

委派類型衍生自 Delegate .NET 中的 類別。 委派類型是 密封的,它們無法衍生自 ,而且無法從 Delegate衍生自定義類別。 因為具現化委派是物件,所以它可以作為參數傳遞,或指派給屬性。 一個方法可以接受委派作為參數,並在稍後的時間呼叫該委派。 這稱為異步回呼,而且是一種在長時間進程完成時通知呼叫端的常見方法。 以這種方式使用委派時,使用委派的程序代碼不需要任何有關所使用方法實作的知識。 此功能類似於封裝介面所提供的功能。

回呼的另一個常見用法是定義自定義比較方法,並將該委派傳遞至排序方法。 它可讓呼叫端的程式代碼成為排序演算法的一部分。 下列範例方法會使用 Del 型別作為參數:

public static void MethodWithCallback(int param1, int param2, Callback 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 實例中。

當委派被叫用時,可以呼叫多個方法,此技術稱為多重呼叫。 若要將額外的方法新增至委派的方法清單—即調用清單,只需要使用加號或加法賦值運算符('+' 或 '+=')新增兩個委派。 例如:

var obj = new MethodClass();
Callback d1 = obj.Method1;
Callback d2 = obj.Method2;
Callback d3 = DelegateMethod;

//Both types of assignment are valid.
Callback allMethodsDelegate = d1 + d2;
allMethodsDelegate += d3;

allMethodsDelegate在其調用清單中包含三個方法:Method1Method2DelegateMethod。 原始的三個委派 d1d2d3保持不變。 叫用 時 allMethodsDelegate ,會依序呼叫這三種方法。 如果委派使用參考參數,則參考會依序傳遞至這三個方法的每一個,而一個方法的任何變更都會顯示在下一個方法中。 當任何方法拋出在方法內未捕捉到的例外狀況時,該例外狀況會傳遞給委派的呼叫端。 不會呼叫調用清單中的後續方法。 如果委派有返回值和/或 out 參數,則會返回最後被呼叫方法的返回值和參數。 若要從調用清單中移除方法,請使用 減法或減法指派運算符--=)。 例如:

//remove Method1
allMethodsDelegate -= d1;

// copy AllMethodsDelegate while removing d2
Callback oneMethodDelegate = (allMethodsDelegate - d2)!;

由於委派類型衍生自 System.Delegate,因此可以在委派上呼叫該類別所定義的方法和屬性。 例如,若要在委派的呼叫清單中查找方法的數目,您可以撰寫:

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

具有多個方法調用列表的委派從 MulticastDelegate 衍生而來,MulticastDelegate 是 的子類別。 此程式代碼可在任一情況下運作,因為這兩個類別都支援 GetInvocationList

多重委派在事件處理中廣泛使用。 事件來源物件會將事件通知傳送給已註冊接收該事件的收件者物件。 為了訂閱事件,接收者會建立用於處理事件的方法,然後為該方法建立委派,並將該委派傳遞至事件來源。 來源會在事件發生時呼叫代理物件。 然後委託代理會在收件者上呼叫事件處理方法,並傳遞事件資料。 事件來源會定義指定事件的委派類型。 如需詳細資訊,請參閱 事件

比較在編譯階段指派的兩種不同類型委派會導致編譯錯誤。 如果委派實例是靜態型別 System.Delegate,則允許進行比較,但在執行時期會傳回 false。 例如:

delegate void Callback1();
delegate void Callback2();

static void method(Callback1 d, Callback2 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);
}

另請參閱