【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
版權宣告:本文為博主原創文章,轉載請附上博文連結!