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