2013年12月12日 星期四

C# Delegates 強大的程式核心武器

有寫過C/C++,就應該知道在C/C++領域裡,指標Function Pointers造就了許多強大軟體入世的核心功能。它等同於武俠小說裡的「九陽真經」一般,用至神一般的境界時,無堅不摧。
C/C++函式指標提供了開發者相當大的彈性,尤其在於功能選單實作,開發者可藉由改變指標指向的函式,輕鬆又漂亮地做出效果,不過函式指標也是 C++ 程式開發中很容易出錯的一環,稍有不慎,就會在除錯時,產生莫名的錯誤,對記憶體的控制不熟練的人而言,使用指標是一種痛苦的開始。
C#的誕生和特性,自然是承襲了C/C++ 和 Java的許多特性。當然,一定少不了和指標相同功能的型別。它就是Delegates,微軟官方中文譯「委派」。

微軟官方的詮釋,Delegates是「定義方法簽章的型別。 當您執行個體化委派時,可以將其執行個體與任何具有相容簽章的方法產生關聯。 您可以透過委派執行個體來叫用 (Invoke) 或呼叫方法。」但它有它獨特的特性:

  • Delegate與 C++ Function Pointers(指標)相似,但為型別安全。
  • Delegate允許將方法(Method)當做參數傳遞。
  • Delegate可用於定義Callback方法。
  • 可將Delegate鏈結在一起,例如,可在單一Event上呼叫多個方法Method。
  • 方法Method不需要完全符合Delegate Sign。
  • C# 2.0 版引進了匿名方法 (Anonymous Method) 的概念,讓程式碼區塊能夠當做參數傳遞,以取代個別定義的方法。 C# 3.0 引進 Lambda 運算式,做為更簡潔的內嵌 (Inline) 程式碼區塊撰寫方式。 匿名方法與 Lambda 運算式 (在特定內容中) 都會編譯為委派型別 (Delegate Type)。 現在,這些功能合稱為「匿名函式」(Anonymous Function)。 如需 Lambda 運算式的詳細資訊,請參閱 匿名函式 (C# 程式設計手冊)。

Delegate是可以安全封裝方法的型別,類似 C/C++ 中的Function Pointers。 與 C/C++ Function Pointers不同的是,Delegate是物件導向、型別和本身較安全。更精準來說,Delegate 是 C# 的特殊型別,用來定義方法(method/function)的 signature,delegate 的實體(instance)可以存放一或多個符合該 signature 的方法。

public delegate void Del(string message);

// Create a method for a delegate. 
public static void DelegateMethod(string message)
{
    System.Console.WriteLine(message);

}
  • C#必須自己宣告(Declare) Delegate才能使用Event。
  • 委派可以將方法當成參數來進行傳遞
Delegate宣告(Declare):
[public|private|proected] Delegate [void | 回傳資料型態] 委派名稱 ([參數群一]);
  • Delegate是event的基礎,可以讓Delegate來呼叫不同的event,能觸發其他控制項事件來完成互動性的應用程式。
Event宣告(Declare)結構: 
public event ClickEventHandler ClickEvent;
[public|private|proected] + event + Delegate的方法 + Event名稱 ;
  • Delegate可用於向某個Class傳遞註冊過的方法,註冊的Method的參數必須和Delegate方法完全一致。

使用Delegate傳遞方法
1.建立方法(Method)
有回傳值的程式結構
public int ReturnMethod(int a, int b)
{
    Console.WriteLine("呼叫傳值,第一個是參數是 {0}, 第二個參數是 {1}", a, b);

    if (a > 0 && b <= 0) return a;
    if (b > 0 && a <= 0) return b;
    if (a > 0 && b > 0) return a + b;

}

沒有回傳值的程式結構
public static void StaticMethod()
{
     Console.WriteLine("靜態呼叫");

}

2.宣告Delegate和參數,要與被呼叫的方法一樣,包含回傳型別。

private delegate void DoDelegate();

private delegate int DelegateParam(int a, int b);

3.實體化Delegate (new),要指定方法

DoDelegate Dd = new DoDelegate(MyClass.StaticMethod);

4.呼叫函數的方式

Dd.Invoke(); (可用Dd();呼叫)


使用Event傳遞方法
「事件(Event)」,就是某一件發生在程式裡的事,其他Object可以針對該事件做出回應。

1.建立事件函數
修飾詞最好是protected virtual,子類別能直接覆寫Event觸發的定義
private void ButtonClick(object sender, EventArgs e)
{
  //事件觸發

}

2.委派宣告
public delegate void ClickEventHandler(object sender, EventArgs e);

3.創建類別
public class Button { }

4.宣告的事件
public event ClickEventHandler ClickEvent;

5.建立成員方法
public void Click()

6.丟出(out)事件Event,給所有相對應按收事件的方法。
ClickEvent(this, null);

public class Button
{
     public event ClickEventHandler ClickEvent;
     public void Click()
     {
          if (ClickEvent != null) ClickEvent(this, null);
     }

}

7.Class實體化(new)
public Button button = new Button();

8.Event實體化(new),註冊Event
Button.ClickEvent += new ClickEventHandler(ButtonClick);

private void CreateForm1(object sender, EventArgs e)
{
     Form1 form = new Form1();
     form.Button.Click();

}

上面是使用的方法,當然還有千變萬化的方法,這是基本的程式結構,Delegate一個特性,就是「依序」,一旦 delegate 被呼叫,它會依照指定的順序執行方法。例如數量的運算上,透過Delegate,可以很只要透過+=或-=,而達到許多數學運算的結果。
public delegate string GetResult(int amount);
class FirtstDelegate
{
    public static string Method1(int amount)
    {
        Console.WriteLine("Delegate's method1 " + (amount + 1));
        return "FirstLine";
    }

    public static string Method2(int amount)
    {
        Console.WriteLine("Delegate's method2 " + (amount + 2));
        return "SecondLine";
    }

    public static void Main()
    {
        GetResult getResult = new GetResult(Method1);
        getResult += Method2;
        Console.WriteLine(getResult(5));
    }

}

Delegate 可以做到 Callback 的效果,類似 event ,但是 Callback method 只有一個,Event handler 可以很多個,做到確認 delegate 所指向的方法數量,最重要的是將 delegate 標示為 private,並且以「=」代替「+=」。但是將修飾子變成 private 還是會被相同Class所產生的實體存取。

Event與Callback的不同是 - Event是Global Out的Publish方式,Class向全世界Publish某特定事項已經發生的方式。Callback不會被Publish,它是Private,對於它要呼叫誰有絕對的控制權。


-雲遊山水為知已逍遙一生而忘齡- 電腦神手

沒有留言:

張貼留言