C#快速入門教程(17)—— 委託、事件與Lambda表示式
圖形化使用者介面(GUI)中,當我們單擊一個按鈕時就會有一個響應操作,這就是啟用了按鈕的單擊(click)事件(event);但是,在建立按鈕元件時並不能決定單擊按鈕後會有什麼操作,比如“確定”和“取消”就是完全不同的操作,此時,只能將按鈕單擊事件的響應程式碼交給使用按鈕的開發者來編寫。
在軟體開發中,還會許多類似的情形出現,比如,某個元件需要特定的操作,但在開發時無法確認具體的實現,或者使用者可以自定義操作;此時,就可以通過一種機制,讓元件的使用者來編寫實現程式碼。在C#中,可以使用委託(delegate)來處理這種情況,而事件則是委託的一種應用形式。
下面的示例,假設在軟體執行過程中需要做一些記錄,以便能夠更有效地分析軟體使用過程中的問題,但是,開發日誌記錄元件時並不確定使用什麼形式儲存資料,如使用檔案、資料庫等,此時,就可以使用委託來解決。
下面的程式碼,我們定義了一個名為DLogger的委託型別。
namespace ConsoleTest
{
public delegate void DLogger(string msg);
}
程式碼中可以看到,除了delegate關鍵字,其他的內容與方法的定義非常相似,沒錯,因為很多情況下,委託就是通過方法完成具體的工作。
下面的程式碼,我們建立了CLog類,用於完成日誌的記錄工作。
public static class CLog
{
public static DLogger Logger = new DLogger(DefaultLogger);
// 預設的處理方法
private static void DefaultLogger(string msg)
{
Console.WriteLine("預設操作");
Console.WriteLine(msg);
}
// 日誌記錄方法
public static void Log(string msg)
{
Logger(msg);
}
//
}
在一個專案中,日誌記錄操作的方式應該是一致的,所以,我們將CLog類定義為靜態類,其成員也都是靜態的,其中:
- Logger物件定義為DLogger委託型別,並初始化為呼叫DefaultLogger()方法。
- DefaultLogger()方法,用於預設的日誌記錄操作。
- Log()方法,提供給使用者呼叫的日誌記錄方法。
下面的程式碼,我們試用一下CLog.Log()方法的預設執行效果。
static void Main(string[] args)
{
CLog.Log("Hello Delegate");
}
程式碼執行結果如下圖所示。
那麼,我們如何修改CLog.Log()方法的操作呢?下面的程式碼就可以做到。
static void Main(string[] args)
{
// 修改日誌委託的實現
CLog.Logger = new DLogger(WriteLog);
//
CLog.Log("Hello Delegate");
}
//
static void WriteLog(string msg)
{
Console.WriteLine("日誌寫入資料庫");
Console.WriteLine(msg);
}
程式碼中,我們定義了一個WriteLog()方法,請注意它的返回值和引數設定應與DLogger委託型別保持一致;然後,在Main()方法中,將CLog.Logger重新設定為呼叫WriteLog()方法;執行結果如下圖所示。
示例中,大家可以看到,WriteLog()方法在整個軟體中只需要呼叫一次即可,此時單獨定義一個方法顯得有些多餘;在這種情況下,我們可以使用Lambda表示式來完成相同的任務,如下面的程式碼。
static void Main(string[] args)
{
//
CLog.Logger = (string msg) =>
{
Console.WriteLine("日誌寫入資料庫");
Console.WriteLine(msg);
};
//
CLog.Log("Hello Delegate");
}
這裡,使用Lambda表示式重新設定了CLog.Logger委託物件的操作,此處使用=>符號,這是Lambda表示式的標誌,而Lambda表示式定義的格式如下。
(<引數列表>) => {
<語句塊>
};
我們可以看到,Lambda表示式的定義非常像一個簡化的方法定義,只是沒有了方法名,而且不需要指定返回值型別;實際上,Lambda表示式的是可以返回資料的,只需要在<語句塊>中使用return語句返回資料即可,就像方法的實現一樣。如下面的程式碼。
// 加法運算委託
delegate int DSum(int x, int y);
//
static void Main(string[] args)
{
//
DSum sum = (int num1, int num2) =>
{
return num1 + num2;
};
//
int x = 10;
int y = 99;
Console.WriteLine("{0}+{1}={2}", x, y, sum(x, y));
}
本例中,我們定義了DSum委託型別,它包括兩個int型別的引數,其返回值同樣是int型別。Main()方法中,我們使用Lambda表示式定義了sum物件(DSum委託型別)的實現,其中將返回兩個引數相加的和。程式碼執行結果如下圖所示。
以上,我們看到了如何使用方法和Lambda表示式來實現委託物件的具體操作,在實際應用中,如果委託型別沒有返回值,我們還可以使用一個委託物件同時完成多個實現,如下面的程式碼。
static void Main(string[] args)
{
CLog.Logger = new DLogger(WriteLog);
CLog.Logger += new DLogger(SendLog);
//
CLog.Log("多路廣播委託");
}
//
static void WriteLog(string msg)
{
Console.WriteLine("日誌寫入資料庫");
Console.WriteLine(msg);
}
//
static void SendLog(string msg)
{
Console.WriteLine("日誌傳送到遠端伺服器");
Console.WriteLine(msg);
}
本例,我們定義了兩個方法,分別是WriteLog()和SendLog()方法,它們的引數和DLogger委託型別定義的相同的,並且沒有返回值。Main()方法中,我們通過=和+=運算子將兩個方法的實現都新增到了CLog.Logger委託物件中,當呼叫CLog.Log()方法時,就會呼叫WriteLog()和SendLog()兩個方法,執行結果如下圖所示。
如果大家設計軟體的圖形介面就會發現,控制元件(如按鈕)的事件的響應方法就是這樣進行關聯的,而這種操作就叫做多路廣播委託(multicast delegate),簡稱多播委託。
CHY軟體小屋原創作品!
相關文章
- C# 委託,事件和Lambda表示式 (轉)C#事件
- 委託、Lambda表示式、事件系列05,Action委託與閉包事件
- 委託、Lambda表示式、事件系列03,從委託到Lamda表示式事件
- .NET委託,事件和Lambda表示式事件
- 委託、Lambda表示式、事件系列07,使用EventHandler委託事件
- C# 委託(delegate)、泛型委託和Lambda表示式C#泛型
- 委託、Lambda表示式、事件系列02,什麼時候該用委託事件
- C#中的委託,匿名方法和Lambda表示式C#
- lambda表示式——快速入門
- 用 Lambda表示式傳遞委託
- 委託、Lambda表示式、事件系列01,委託是什麼,委託的基本用法,委託的Method和Target屬性事件
- 五分鐘重溫C#委託,匿名方法,Lambda,泛型委託,表示式樹C#泛型
- C#委託與事件C#事件
- C# - 委託與事件C#事件
- 委託、Lambda表示式、事件系列04,委託鏈是怎樣形成的, 多播委託, 呼叫委託鏈方法,委託鏈異常處理事件
- 委託、Lambda表示式、事件系列06,使用Action實現觀察者模式,體驗委託和事件的區別事件模式
- C# 之委託與事件C#事件
- C#快速入門教程(20)—— 字串與正規表示式C#字串
- 五分鐘重溫委託,匿名方法,Lambda,泛型委託,表示式樹泛型
- 【UNITY3D 遊戲開發之七】C# 中的委託、事件、匿名函式、Lambda 表示式Unity3D遊戲開發C#事件函式
- 詳解C#委託與事件C#事件
- C# 事件委託C#事件
- C# 委託事件C#事件
- 詳解C#委託,事件與回撥函式C#事件函式
- C# 事件 vs 委託C#事件
- c# 委託和事件C#事件
- 委託與事件-委託詳解(一)事件
- 重中之重:委託與事件事件
- Js 事件原理與事件委託JS事件
- C# 從1到Core--委託與事件C#事件
- C#程式設計之委託與事件(一)C#程式設計事件
- C#程式設計之委託與事件(二)C#程式設計事件
- javascript快速入門17--事件JavaScript事件
- C#:委託和自定義事件C#事件
- C# 中的委託和事件C#事件
- 3分鐘入門lambda表示式
- jdk1.8 lambda表示式入門JDK
- Java入門:Lambda常用表示式解析Java