【C#学习】delegate(委托) 和 event(事件)
C# 中的委托(Delegate)類似于 C 或 C++ 中函數(shù)的指針。委托(Delegate) 是存有對某個(gè)方法的引用的一種引用類型變量。引用可在運(yùn)行時(shí)被改變。在C#中方法不能作為參數(shù)直接傳遞,必須使用委托(用來委托方法)。delegate(委托)是一種特殊的引用類型,它將方法也作為特殊的對象封裝起來,從而將方法作為變量、參數(shù)或者返回值傳遞。委托(Delegate)特別用于實(shí)現(xiàn)事件和回調(diào)方法。所有的委托(Delegate)都派生自 System.Delegate 類。使用一個(gè)委托有三個(gè)步驟:?
定義委托
實(shí)例化委托
將指定的方法添加到委托對象中
例子:
? ? ? ? delegate int plus(int x, int y); // 1. 定義委托
?
? ? ? ? static void Main(string[] args)
? ? ? ? {
? ? ? ? ? ? plus del_p; ?// 2. 實(shí)例化委托
?
? ? ? ? ? ? del_p = new plus(addition); ?// 3. 將方法添加到實(shí)例化委托對象中
?
? ? ? ? ? ? int n = del_p(1, 2);
? ? ? ? ? ? Console.Write(n);
? ? ? ? }
?
? ? ? ? static int addition(int x, int y)
? ? ? ? {
? ? ? ? ? ? return x + y; ?
? ? ? ? }
C#允許直接把方法名賦給委托,所以下面的三種寫法也正確:
? ? ? ? ? ? plus del_p = new plus(addition);
? ? ? ? ? ? plus del_p2 = addition;
? ? ? ? ? ? del_p = addition;?
委托完全可以被當(dāng)做普通類型對待,比如可以加減、賦值、構(gòu)建數(shù)組。
委托數(shù)組
委托可以構(gòu)建數(shù)組,意味著一組同樣返回類型和參數(shù)類型的方法。
? ? ? ? delegate int MathFunc(int x, int y);?
?
? ? ? ? static void Main(string[] args)
? ? ? ? {
? ? ? ? ? ? MathFunc[] fs = new MathFunc[]
? ? ? ? ? ? {
? ? ? ? ? ? ? ? substract,?
? ? ? ? ? ? ? ? addition,?
? ? ? ? ? ? ? ? product,
? ? ? ? ? ? ? ? division
? ? ? ? ? ? };
?
? ? ? ? ? ? int n = fs[0](1, 2); // -1
? ? ? ? }
?
? ? ? ? static int division( int x, int y)
? ? ? ? {
? ? ? ? ? ? return x / y;
? ? ? ? }
?
? ? ? ? static int substract(int x, int y)
? ? ? ? {
? ? ? ? ? ? return x - y;?
? ? ? ? }
?
? ? ? ? static int addition(int x, int y)
? ? ? ? {
? ? ? ? ? ? return x + y; ?
? ? ? ? }
?
? ? ? ? static int product(int x, int y)
? ? ? ? {
? ? ? ? ? ? return x * y;
? ? ? ? }
委托的加減法/委托的多播(Multicasting of a Delegate)
一個(gè)委托對象可以封裝多個(gè)方法,通過委托對象的合并(加法)實(shí)現(xiàn)。被合并的方法必須有相同的返回類型和參數(shù)類型。使用合并后的委托時(shí),會依次將實(shí)參傳入被合并的方法,最后的返回值以最后一個(gè)方法為準(zhǔn)。
? ? ? ? delegate int MathFunc(int x, int y);?
?
? ? ? ? static void Main(string[] args)
? ? ? ? {
? ? ? ? ? ? MathFunc f;
? ? ? ? ? ? f = addition;
? ? ? ? ? ? f += substract;
? ? ? ? ? ? f += product;
? ? ? ? ? ? int n = f(1, 2); // 2
? ? ? ? }
?
? ? ? ? static int division( int x, int y)
? ? ? ? {
? ? ? ? ? ? Console.WriteLine("division");
? ? ? ? ? ? return x / y;
? ? ? ? }
?
? ? ? ? static int substract(int x, int y)
? ? ? ? {
? ? ? ? ? ? Console.WriteLine("substraction");
? ? ? ? ? ? return x - y;?
? ? ? ? }
?
? ? ? ? static int addition(int x, int y)
? ? ? ? {
? ? ? ? ? ? Console.WriteLine("addition");
? ? ? ? ? ? return x + y; ?
? ? ? ? }
?
? ? ? ? static int product(int x, int y)
? ? ? ? {
? ? ? ? ? ? Console.WriteLine("product");
? ? ? ? ? ? return x * y;
? ? ? ? }
上面的代碼會打印出:
addition?
substraction?
product?
委托減法是加法的逆運(yùn)算。如果被減委托中不含有減數(shù)委托,則不會對被減數(shù)造成任何影響,被減數(shù)減去自身為null,調(diào)用空委托會引發(fā)異常。總結(jié)下來委托加減法的幾個(gè)結(jié)論:
委托加減null沒有任何效果
委托減自身為null
減數(shù)如果沒有包含在被減數(shù)中,則沒有任何效果
在使用委托之前,應(yīng)該判斷委托是否為null。
傳遞委托
委托可以被作為以下方式傳遞
變量
方法參數(shù)
方法返回值
? ? ? ? delegate int MathFunc(int x, int y);?
?
? ? ? ? static void Main(string[] args)
? ? ? ? {
? ? ? ? ? ? MathFunc f = getAddFunc();
? ? ? ? ? ? int n = f(2, 3); // 5
? ? ? ? ? ? int n2 = add(f, 3, 4); // 7
? ? ? ? }
?
? ? ? ? static int add(MathFunc f, int x, int y)
? ? ? ? {
? ? ? ? ? ? return f(x, ?y);
? ? ? ? }
?
? ? ? ? static MathFunc getAddFunc()
? ? ? ? {
? ? ? ? ? ? return addition;
? ? ? ? ? ? // or return new MathFunc(addition);
? ? ? ? }
匿名方法(delegate方法)
使用 delegate 關(guān)鍵字直接定義方法,和實(shí)例化委托不同,不使用 new 關(guān)鍵字來創(chuàng)建委托對象,而是直接定義方法參數(shù)和方法體。匿名方法并不是真的沒有名稱,而是指程序員無需命名。C#在編譯時(shí)會給方法生成一個(gè)方法定義(包含方法名和參數(shù)列表),該方法實(shí)際上是當(dāng)前類型的一個(gè)私有靜態(tài)方法。
? ? ? ? delegate int MathFunc(int x, int y);?
?
? ? ? ? static void Main(string[] args)
? ? ? ? {
? ? ? ? ? ? MathFunc f = delegate (int x, int y)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? return x + y;
? ? ? ? ? ? };
? ? ? ? ? ? int n = f(1, 2); // 3
? ? ? ? }
Lambda表達(dá)式
從C# 3.0 開始,可以用 lambda表達(dá)式替換匿名方法表達(dá)式,直接將一個(gè) Lambda表達(dá)式賦給委托對象。注意Lambda表達(dá)式不能作為語句,必須為右值。Lambda表達(dá)式的參數(shù)和返回類型必須和委托一致。
? ? ? ? delegate int MathFunc(int x, int y);?
?
? ? ? ? static void Main(string[] args)
? ? ? ? {
? ? ? ? ? ? MathFunc f;
? ? ? ? ? ? f = (int x, int y) =>
? ? ? ? ? ? {
? ? ? ? ? ? ? ? return x + y;
? ? ? ? ? ? };
? ? ? ? ? ? int n = f(1, 2); // 3
? ? ? ? }
如果lambda表達(dá)式只有一個(gè)參數(shù),則可以省略圓括號。Lambda表達(dá)式允許多種寫法,以下寫法等價(jià):
? ? ? ? ? ? something = (int x, int y) => { return x + y; };
? ? ? ? ? ? something = (int x, int y) => x + y;
? ? ? ? ? ? something = (x, y) => x + y;
? ? ? ? ? ? something = (x, y) => { return x + y; };?
Lambda表達(dá)式中沒有用到的參數(shù)可以用 _ 代替。比如
something = (x, _) => x * 2;?
在Lambda表達(dá)式和匿名delegate方法內(nèi)部都可以訪問主調(diào)函數(shù)的外部變量,比如:
? ? ? ? ? ? MathFunc f;
? ? ? ? ? ? string str = "str";
? ? ? ? ? ? f = (x, y) =>
? ? ? ? ? ? {
? ? ? ? ? ? ? ? Console.Write(str); // 訪問了外部的str
? ? ? ? ? ? ? ? return x + y;
? ? ? ? ? ? };
如果Lambda表達(dá)式或者匿名delegate方法的參數(shù)名和外部變量沖突,則無法通過編譯。
委托發(fā)布和訂閱
基于委托多播的特性,可以實(shí)現(xiàn) “發(fā)布者/訂閱者”模式。發(fā)布者對象有一個(gè)委托成員,保存一系列別的類的實(shí)例(訂閱者)的方法,一旦發(fā)布者觸發(fā)(調(diào)用)了委托,就會把所有注冊過的方法都依次調(diào)用依次,通知訂閱者。比如有一個(gè)紅綠燈,一旦紅綠燈變色,就會通知所有車輛和行人,此時(shí)可以把車輛和行人的響應(yīng)方法注冊到紅綠燈對象的一個(gè) public 委托成員 OnColorChange 里,當(dāng)紅綠燈調(diào)用 OnColorChange 時(shí),就會通知所有車輛,調(diào)用他們的響應(yīng)函數(shù)。由于訂閱者的類型和響應(yīng)方法千奇百怪,可以高度定制針對一個(gè)事件(比如紅綠燈變色)的不同對象的不同響應(yīng)函數(shù)。
由于委托成員 OnColorChange 是公有的,一旦別的程序?qū)⑽兄脼榭?#xff0c;或其他值,委托先前的修改就前功盡棄了。為了防止這種事情發(fā)生,C# 提供了?event 來修飾(聲明)委托成員。經(jīng)過 event 修飾后,委托成員只能被 += 和 -= 修改,而不能用 = 修改。
---------------------?
作者:csdn_chai?
來源:CSDN?
原文:https://blog.csdn.net/csdn_chai/article/details/77429538?
版權(quán)聲明:本文為博主原創(chuàng)文章,轉(zhuǎn)載請附上博文鏈接!
總結(jié)
以上是生活随笔為你收集整理的【C#学习】delegate(委托) 和 event(事件)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 大白话系列之C#委托与事件讲解大结局
- 下一篇: C# 委托(Delegate)