如果我們想將函數(shù)作為參數(shù)傳遞怎么辦?C#如何處理回調(diào)函數(shù)或事件處理程序?答案是-委托(delegate)。委托(Delegate) 是存有對某個(gè)方法的引用的一種引用類型變量。引用可在運(yùn)行時(shí)被改變。
委托是定義方法簽名的引用類型數(shù)據(jù)類型。您可以定義委托的變量,就像其他數(shù)據(jù)類型一樣,這些變量可以引用與委托具有相同簽名的任何方法。
與委托一起工作涉及三個(gè)步驟:
聲明委托
設(shè)置目標(biāo)方法
調(diào)用委托
可以使用delegate關(guān)鍵字和函數(shù)簽名來聲明委托,如下所示。
委托語法
[access modifier] delegate [return type] [delegate name]([parameters])
以下聲明了一個(gè)名為 MyDelegate 的委托。
public delegate void MyDelegate(string msg);
上面,我們聲明了一個(gè) MyDelegate 帶有
聲明委托后,我們需要設(shè)置目標(biāo)方法 或 lambda表達(dá)式。我們可以通過使用 new 關(guān)鍵字創(chuàng)建委托的對象并傳遞其簽名與委托簽名匹配的方法來實(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); }
您可以通過直接分配方法來設(shè)置目標(biāo)方法,而無需創(chuàng)建委托的對象,例如MyDelegate del = MethodA。
設(shè)置目標(biāo)方法后,可以使用 Invoke()方法或使用()運(yùn)算符來調(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); } }
下圖說明了委托。
方法可以具有委托類型的參數(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)該用于最常見的委托,而不是創(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ù)類型。
委托類型變量可以引用具有與委托相同簽名的任何方法。
語法:[訪問修飾符]委托[返回類型] [委托名稱]([參數(shù)])([access modifier] delegate [return type] [delegate name]([parameters]))
目標(biāo)方法的簽名必須與委托簽名匹配。
委托可以像普通函數(shù)或invoke()方法一樣被調(diào)用。
可以使用“ +”或“ + =”運(yùn)算符將多個(gè)方法分配給委托,并使用“-”或“-=”運(yùn)算符將其刪除。它稱為多播委托。
如果多播委托返回一個(gè)值,則它從最后分配的目標(biāo)方法中返回該值。
委托用于在C#中聲明事件和匿名方法。