- 從 Lambda 使用至今,所使用的範圍越來越廣,而 Lambda 原型為 Delegate,因此需要詳細的了解此原理:Lambda 運算式 (C# 程式設計手冊)
- Delegate
- 使用 Delegate 關鍵字
- Delegate 為型別,可以放在 namespace
- 宣告 Delegate 步驟
- Declare delegate & Declare function to delegate
- 宣告的"函數回傳類型"與"引數的數目與類型"需完全相同
- Create delegate reference
- Point the reference to the add method
- Invoke the delegate
- Code
///
/// (1A) Delcare delegate
/// 每個 delegate 型別"封裝"
/// I. 函數回傳類型
/// II.引數的數目與類型
///
public delegate string ReturnMessage(string message);
///
/// Using Delegate
///
public class DelegateLib
{
///
/// (2) Create delegate reference
///
public ReturnMessage returnMessage = null;
///
/// Demo the function.
///
public void DemoFunction()
{
// (4) Invoke the method through delegate object
returnMessage("DelegateLib:Lyndon"); // 相同 returnMessage.invoke("Lyndon");
}
}
///
/// (1B) Delcare function to delegate
/// 定義符合 Delegate 型別的方法
/// 需相同於
/// I. 函數回傳類型
/// II.引數的數目與類型
///
static string ShowMessage(string message)
{
Console.WriteLine(string.Format("Program:{0}", message));
// return message
return message;
}
static void Main(string[] args)
{
DelegateLib demoDelegate = new DelegateLib();
// (3) Point the reference to the add method
// delegate 支援多點傳送,因繼承System.MulticastDelegate類別
// = : 將方法指定至 delegate
// += : 將多個方法綁定到同個 delegate
// demoDelegate.returnMessage += ShowMessage;
// -= : 將某個 delegate 參考從 delegate 清單中移除
// demoDelegate.returnMessage -= ShowMessage;
// null : 移除所有委派
// demoDelegate.returnMessage = null;
// [Design Pattern - Observer]
// 應避免此情況:
// 對於客戶端,應該透過註冊/取消來操作自己對應事件,不應該任意進行賦值操作
// 不小心將其他發佈者 delegate 類別直接賦值 null,將會取消掉發佈者所有的通知列表
// 發佈事件通知應該由發佈者來觸發,不應該讓客戶端可以呼叫
demoDelegate.returnMessage = ShowMessage; // 不強制 += / -=
demoDelegate.DemoFunction();
}
- 沒有使用 event 的情況下,可以針對 delegate 進行任何的操作,因此風險很高
- Delegate and Event
- Code 將 (2) Delcare event 進行改變
///
/// (1A) Delcare delegate
/// 每個 delegate 型別"封裝"
/// I. 函數回傳類型
/// II.引數的數目與類型
///
public delegate string ReturnMessage(string message);
public class DelegateEventLib
{
///
/// (2) Delcare event
/// 避免使用 delegate 可能會破壞物件封裝性的問題
/// I. delegate 可隨意進行賦值操作,若不小心使用者將會移除所有事件
/// 所以利用 event 封裝 delegate 類型的變數,因此類別的外部,使用者透過 "+=" 和 "-=" 進行事件操作
/// II.delegate 可以綁定特定的方法,宣告必須定義 public
/// 但也破壞掉物件的封裝性特性,因為類別的內外都可以呼叫 delegate
///
public event ReturnMessage returnMessage = null;
///
/// Demo the function.
///
public void DemoFunction()
{
// (4) Invoke the method through delegate object
returnMessage("DelegateEventLib:Lyndon"); // 相同 returnMessage.invoke("Lyndon");
}
}
///
/// (1B) Delcare function to delegate
/// 定義符合 Delegate 型別的方法
/// 需相同於
/// I. 函數回傳類型
/// II.引數的數目與類型
///
/// The message.
/// string
static string ShowMessage(string message)
{
Console.WriteLine(string.Format("Program:{0}", message));
// return message
return message;
}
static void Main(string[] args)
{
DelegateEventLib demoDelegateEvent = new DelegateEventLib();
// (3) Point the reference to the add method
// delegate 支援多點傳送,因繼承System.MulticastDelegate類別
// += : 將多個方法綁定到同個 delegate
// demoDelegate.returnMessage += ShowMessage;
// -= : 將某個 delegate 參考從 delegate 清單中移除
// demoDelegate.returnMessage -= ShowMessage;
demoDelegateEvent.returnMessage += ShowMessage; // 強制 += / -=
demoDelegateEvent.DemoFunction();
}
- Func and Action (C# 2.0)
- 內建提供兩種不同的委派
- Func<T, TResult> 委派
- 提供回傳值方法
- in T: 這個委派所封裝之方法的參數類型
- out TResult: 這個委派所封裝之方法的傳回值之類型
- Code:將 DelegateEventLib 程式碼,進行修改,行為相完全相同
public class DelegateEventLib
{
///
/// (2) Delcare event
/// 避免使用 delegate 可能會破壞物件封裝性的問題
/// I. delegate 可隨意進行賦值操作,若不小心使用者將會移除所有事件
/// 所以利用 event 封裝 delegate 類型的變數,因此類別的外部,使用者透過 "+=" 和 "-=" 進行事件操作
/// II.delegate 可以綁定特定的方法,宣告必須定義 public
/// 但也破壞掉物件的封裝性特性,因為類別的內外都可以呼叫 delegate
///
public event Func< string, string> returnMessage = null;
///
/// Demo the function.
///
public void DemoFunction()
{
// (4) Invoke the method through delegate object
returnMessage("DelegateEventLib:Lyndon"); // 相同 returnMessage.invoke("Lyndon");
}
}
- Action<T> 委派
- 未提供回傳值方法
- in T: 這個委派所封裝之方法的參數類型
- 如果上列宣告 string ShowMessage(string message) 為 void ShowMessage(string message)沒有回傳值,將可使用 Action 委派
- Code
public class DelegateEventLib
{
///
/// (2) Delcare event
/// 避免使用 delegate 可能會破壞物件封裝性的問題
/// I. delegate 可隨意進行賦值操作,若不小心使用者將會移除所有事件
/// 所以利用 event 封裝 delegate 類型的變數,因此類別的外部,使用者透過 "+=" 和 "-=" 進行事件操作
/// II.delegate 可以綁定特定的方法,宣告必須定義 public
/// 但也破壞掉物件的封裝性特性,因為類別的內外都可以呼叫 delegate
///
public event Action< string> returnMessage = null;
///
/// Demo the function.
///
public void DemoFunction()
{
// (4) Invoke the method through delegate object
returnMessage("DelegateEventLib:Lyndon"); // 相同 returnMessage.invoke("Lyndon");
}
}
- EventHandler 委派 (觸發事件)
- Ref:
沒有留言:
張貼留言