1. 委派語法

  • 委派 (Delegate) 類似於 C/C++ 中的函式指針,是可存有對某個方法的引用的一種引用類型變數。
  • 宣告語法:delegate <return type> <delegate-name> <parameter list>
// 宣告一個委派,裝載 void function(string)
public delegate void PrintString(string text);
public static void Main(string[] args)
{
    // 新增一個委派事件,指向 ToUpperCase
    PrintString e = new PrintString(ToUpperCase);
    string text = "Hello World!";
    e.Invoke(text);
    // HELLO WORLD!

    // 將另一個事件加到委派中,指向 ToLowerCase   
    e += ToLowerCase;
    e.Invoke(text);
    // HELLO WORLD!
    // hello world!
    
    // 將委派中的 ToUpperCase 取消掉
    e -= ToUpperCase;
    e.Invoke(text);
    // hello world!
}
public static void ToUpperCase(string text) {
    Console.WriteLine(text.ToUpper());
}
public static void ToLowerCase(string text) => Console.WriteLine(text.ToLower());

2. 簡化事件註冊

  • 假設想為一個按鍵註冊事件:
// 定義 EventHandler 為可以接收物件與傳參的委派
public delegate void EventHandler(object sender, EventArgs e);

// 定義傳參可以儲存的內容
public class HandleClickEventArgs : EventArgs
{
    public string Message;
}
// 創建一個按鍵並為其創建一個可以註冊事件的委派
public class Button
{
    public string name;
    public Button(string _name)
    {
        name = _name;
    }
    // 在物件內部定義一個委派存放事件
    private event EventHandler Click;
    public notify()
    {
        // 執行委派
        // Handler.Invoke(this, e);
        Handler(this, e);
    }
}
// 註冊事件的傳參需與委派的傳參一致
private static void Click(object sender, EventArgs e)
{
    Console.WriteLine(
        sender.GetType() + " " + 
        (e as HandleClickEventArgs)?.Message
    );
}
public void static Main(string[] args)
{
    EventArgs = new HandleClikEventArgs()
    {
        Message = "is clicked!"
    };
        Button button = new Button("TV Remote Button");
        button.Click += new EventHandler(Click);
        button.Click += Click;
        button.Click += delegate
        {
            Console.WriteLine("Check! Check!");
        };
        button.Click += (sender, e) => Console.WriteLine(
            (sender as Button)?.name + " " +
            (e as HandleClickEventArgs)?.Message
        );
        button.notify(e);
    // Button is clicked!
    // Button is clicked!
    // Check! Check!
    // TV Remote Button is clicked!
}
  • 注意到 Button 內有一個委派被定義為 delegate void function(object sender, EventArgs e),並被命名為 Click,故我們會向它註冊事件。
    • 在 C#1 中,完整的寫法是:
      • button.Click += new EventHandler(Click);
    • 在 C#2,透過 Method group conversion 可將其簡化成(條件是兩者的傳參要相同):
      • button.Click += Click;
    • 如果方法較簡單也可以透過匿名方法(anonymous method)註冊:
      • 需要傳參時:
        • button.Click += delegate(object sender, EventArgs e) { Console.WriteLine("Click!"); };
      • 不需要傳參時:
        • button.Click += delegate { Console.WriteLine("Click!"); };
    • 在 C#3 中,可以透過 Lambda 表達式來創建。
      • button.Click += (sender, e) => Console.WriteLine("Click!");