如果我們想將函數(shù)作為參數(shù)傳遞怎么辦?C#如何處理回調(diào)函數(shù)或事件處理程序?答案是-委托(delegate)。委托(Delegate) 是存有對(duì)某個(gè)方法的引用的一種引用類型變量。引用可在運(yùn)行時(shí)被改變。
委托是定義方法簽名的引用類型數(shù)據(jù)類型。您可以定義委托的變量,就像其他數(shù)據(jù)類型一樣,這些變量可以引用與委托具有相同簽名的任何方法。
與委托一起工作涉及三個(gè)步驟:
聲明委托
設(shè)置目標(biāo)方法
調(diào)用委托
可以使用delegate關(guān)鍵字和函數(shù)簽名來(lái)聲明委托,如下所示。
委托語(yǔ)法
[access modifier] delegate [return type] [delegate name]([parameters])
以下聲明了一個(gè)名為 MyDelegate 的委托。
public delegate void MyDelegate(string msg);
上面,我們聲明了一個(gè) MyDelegate 帶有
聲明委托后,我們需要設(shè)置目標(biāo)方法 或 lambda表達(dá)式。我們可以通過(guò)使用 new 關(guān)鍵字創(chuàng)建委托的對(duì)象并傳遞其簽名與委托簽名匹配的方法來(lái)實(shí)現(xiàn)。
public delegate void MyDelegate(string msg); // 聲明委托
//設(shè)定目標(biāo)方法
MyDelegate del = new MyDelegate(MethodA);
// 或者
MyDelegate del = MethodA;
// 或者 lambda 表達(dá)式
MyDelegate del = (string msg) => Console.WriteLine(msg);
// 目標(biāo)方法
static void MethodA(string message)
{
Console.WriteLine(message);
}您可以通過(guò)直接分配方法來(lái)設(shè)置目標(biāo)方法,而無(wú)需創(chuàng)建委托的對(duì)象,例如MyDelegate del = MethodA。
設(shè)置目標(biāo)方法后,可以使用 Invoke()方法或使用()運(yùn)算符來(lái)調(diào)用委托。
del.Invoke("Hello World!");
//或者
del("Hello World!");以下是委托的完整示例。
public delegate void MyDelegate(string msg); //聲明委托
class Program
{
static void Main(string[] args)
{
MyDelegate del = ClassA.MethodA;
del("Hello World");
del = ClassB.MethodB;
del("Hello World");
del = (string msg) => Console.WriteLine("Called lambda expression: " + msg);
del("Hello World");
}
}
class ClassA
{
static void MethodA(string message)
{
Console.WriteLine("Called ClassA.MethodA() with parameter: " + message);
}
}
class ClassB
{
static void MethodB(string message)
{
Console.WriteLine("Called ClassB.MethodB() with parameter: " + message);
}
}下圖說(shuō)明了委托。

方法可以具有委托類型的參數(shù),如下所示。
public delegate void MyDelegate(string msg); //聲明委托
class Program
{
static void Main(string[] args)
{
MyDelegate del = ClassA.MethodA;
InvokeDelegate(del);
del = ClassB.MethodB;
InvokeDelegate(del);
del = (string msg) => Console.WriteLine("Called lambda expression: " + msg);
InvokeDelegate(del);
}
static void InvokeDelegate(MyDelegate del) // MyDelegate類型參數(shù)
{
del("Hello World");
}
}
class ClassA
{
static void MethodA(string message)
{
Console.WriteLine("Called ClassA.MethodA() with parameter: " + message);
}
}
class ClassB
{
static void MethodB(string message)
{
Console.WriteLine("Called ClassB.MethodB() with parameter: " + message);
}
}在.NET中,F(xiàn)unc和Action類型是內(nèi)置的泛型委托,應(yīng)該用于最常見(jiàn)的委托,而不是創(chuàng)建新的自定義委托。
委托可以指向多個(gè)方法。指向多個(gè)方法的委托稱為多播委托?!?”或“+=”運(yùn)算符將函數(shù)添加到調(diào)用列表中,而“-”和“-=”運(yùn)算符將其刪除。
public delegate void MyDelegate(string msg); //宣聲明委托
class Program
{
static void Main(string[] args)
{
MyDelegate del1 = ClassA.MethodA;
MyDelegate del2 = ClassB.MethodB;
MyDelegate del = del1 + del2; // del1 + del2
del("Hello World");
MyDelegate del3 = (string msg) => Console.WriteLine("Called lambda expression: " + msg);
del += del3; // del1 + del2 + del3
del("Hello World");
del = del - del2; // 移除 del2
del("Hello World");
del -= del1 // 移除 del1
del("Hello World");
}
}
class ClassA
{
static void MethodA(string message)
{
Console.WriteLine("Called ClassA.MethodA() with parameter: " + message);
}
}
class ClassB
{
static void MethodB(string message)
{
Console.WriteLine("Called ClassB.MethodB() with parameter: " + message);
}
}加法和減法運(yùn)算符始終作為賦值的一部分工作:del1+=del2;與del1=del1+del2完全等價(jià);減法也是如此。
如果委托返回一個(gè)值,那么當(dāng)多播委托調(diào)用時(shí),最后分配的目標(biāo)方法的值將被返回。
public delegate int MyDelegate(); //聲明委托
class Program
{
static void Main(string[] args)
{
MyDelegate del1 = ClassA.MethodA;
MyDelegate del2 = ClassB.MethodB;
MyDelegate del = del1 + del2;
Console.WriteLine(del());// 返回200
}
}
class ClassA
{
static int MethodA()
{
return 100;
}
}
class ClassB
{
static int MethodB()
{
return 200;
}
}可以使用與委托相同的方式定義泛型委托,但可以使用泛型type參數(shù)或返回類型。 設(shè)置目標(biāo)方法時(shí),必須指定泛型類型。
例如,看以下用于int和string參數(shù)的通用委托。
public delegate T add<T>(T param1, T param2); // 泛型委托
class Program
{
static void Main(string[] args)
{
add<int> sum = Sum;
Console.WriteLine(sum(10, 20));
add<string> con = Concat;
Console.WriteLine(conct("Hello ","World!!"));
}
public static int Sum(int val1, int val2)
{
return val1 + val2;
}
public static string Concat(string str1, string str2)
{
return str1 + str2;
}
}委托還用于聲明事件和匿名方法。
委托是定義簽名的引用類型數(shù)據(jù)類型。
委托類型變量可以引用具有與委托相同簽名的任何方法。
語(yǔ)法:[訪問(wèn)修飾符]委托[返回類型] [委托名稱]([參數(shù)])([access modifier] delegate [return type] [delegate name]([parameters]))
目標(biāo)方法的簽名必須與委托簽名匹配。
委托可以像普通函數(shù)或invoke()方法一樣被調(diào)用。
可以使用“ +”或“ + =”運(yùn)算符將多個(gè)方法分配給委托,并使用“-”或“-=”運(yùn)算符將其刪除。它稱為多播委托。
如果多播委托返回一個(gè)值,則它從最后分配的目標(biāo)方法中返回該值。
委托用于在C#中聲明事件和匿名方法。