almost 3 years ago

什麼是委派

委派是以特定參數清單和傳回型別表示對方法的參考型別。 當您具現化委派時您可以使其執行個體具有相容簽章和傳回型別的所有方法。(MSDN)

白話文來說,委派方法是一種參考型別(Type),可以用來將方法當做引數傳遞給其他方法。

圖為委派型別的宣告範例

為什麼要用委派

從類別的設計者來看,在設計類別時,可能會碰到某個方法需要額外處理,但又不想把該處理想在這個類別裡因為有可能變化很多,又或是無法預先得知處理的規則。
(註:這部份主要參考Huan-Lin的文章)

簡單用個情境來說明委派的用法

維京老大有一艘戰船,這艘船是老大專門買來給小弟用去打劫的(主要原因是因為老大怕死和麻煩),為了維護自身利益,老大定了一個用船契約範本,上面定了兩個規定分別為回傳string型別輸入一個string型別的參數,小弟需要自行寫一份參考老大契約範本的契約,裡面一定要符合這兩項規定,小弟才能拿這份契約去和老大借船,然後執行自行寫的打劫計畫。

依上述的模擬情境來寫個程式碼來看看 ~首先先宣告一個委派方法,這就是維京老大所寫的契約範本,上面規定,小弟的契約裡需要符合兩個條件分別為回傳string型別
輸入一個string型別的參數

public delegate string Attack(string str);

然後小弟1這時想要和老大借船來幹一票大的~~ ,所以開始寫契約,如下,有沒有符合老大的範本要求呢??『回傳string型別』與『輸入一個string型別的參數』,嗯都有,拿去給老大看應該會答應!

public string Attack_Plan1(string str)
    {
        //這邊可以小弟可自訂自已的攻擊計畫
        //反正最後有回傳黃金(string型別)給老大就好
        Console.WriteLine(str);
        return "給老大的黃金" ;

    }

這時小弟1就跑去和老大借船.
老大:嗯很好有符合,~ 努力去(為我)打劫吧!

private void button1_Click(object sender, EventArgs e)
    {
        //C# 2.0寫法
        Attack attack_plan = Attack_Plan1;
        GoToAttackWithBattleShip(attack_plan, "Attack");
    }


    private void GoToAttackWithBattleShip(Attack attack_plan, string str)
    {
        textBox1.Text = attack_plan(str);
    }

其中這時又來個小弟2,他也想要船,但他沒注意到契約範本規則,然後建立了下面的契約,不符合傳入一個string型別的參數

public string Attack_Plan2(int str)
    {       
        return "給老大的黃金" ;
    }

這時它還是傻傻的跑去向老大借船,結果… 就被打斷腿了。

 private void button1_Click(object sender, EventArgs e)
{
        //C# 2.0寫法
        Attack attack_plan = Attack_Plan2;
        GoToAttackWithBattleShip(attack_plan, "Attack");
 }

多重委派

delegate物件具有一種屬性,就是可以使用+運算子將多個物件指派給一個委派執行的個體由於維京老大越來越懶了,他開始討厭一次來一個的模式,於是他就開始使用『多重委派』,出船一次的就可以帶小弟1…2…3 一起去打劫,打完後在回來,維京老大笑哈哈~。

範例程式碼如下。

    //宣告一個抓取名字的委派方法
    public delegate string Attack (string str);

    private void button1_Click( object sender, EventArgs e)
    {
        //C# 2.0寫法
        Attack attack_plan = Attack_Plan1;
        attack_plan += Attack_Plan2;
        GoToAttackWithBattleShip(attack_plan, "Attack" );
    }

    //顯示Page的文字
    private void GoToAttackWithBattleShip( Attack attack_plan, string str)
    {
        textBox1.Text = attack_plan(str);
    }


    public string Attack_Plan1( string str)
    {
        //這邊可以小弟可自訂自已的攻擊計畫
        //反正最後有回傳黃金(string型別)給老大就好
        Console .WriteLine("小弟1執行打劫活動囉~~~" );
        return "給老大的黃金" ;

    }

    public string Attack_Plan2( string str)
    {
        Console .WriteLine("小弟2執行打劫活動囉~~~" );
        return "給老大的黃金" ;
    }

多重委派特性

  • 它會依順序來呼叫
  • 只有相同型別的委派才能加以結合
  • 委派清單不會過濾掉重覆的方法。

我們將上面程式碼再運用+運算子將Attack_Plan1再加一次。則結果如下。

 private void button1_Click(object sender, EventArgs e)
    {
        //C# 2.0寫法
        Attack attack_plan = Attack_Plan1;
        attack_plan += Attack_Plan2;
        attack_plan += Attack_Plan1;
        GoToAttackWithBattleShip(attack_plan, "Attack" );
    }

執行結果

  • 方法不需要完全符合委派型。請參閱在委派中使用變異數 (C# 和 Visual Basic)。

參考資料

http://msdn.microsoft.com/zh-tw/library/ms173171.aspx
http://huan-lin.blogspot.com/2009/01/delegate-revisited-csharp-1-to-2-to-3.html
http://www.dotblogs.com.tw/billchung/Tags/%E5%A7%94%E6%B4%BE/default.aspx
http://marlon.blog.ithome.com.tw/post/894/61431

← 物件導向系列菜單9-『物件導向特性-封裝(Encapsulation)』 物件導向系列菜單11-『泛型(Generics)』 →
 
comments powered by Disqus