<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    C#之委托

    從一開始接觸C#到現(xiàn)在,委托對我來說都是一道坎,曾經(jīng)想要避開,可是每次寫、看C#程序都避免不了接觸這玩意兒,每次都會覺得很憋屈!所以這幾天想下點苦功夫一下子徹底搞懂它,下面說說自己的見解吧~~

    一、什么是委托
    對于這個詞,一開始接觸的時候很陌生,這也導(dǎo)致了我的畏懼心理,后來學(xué)習(xí)設(shè)計模式的時候知道了委托模型,當(dāng)時也不怎么搞的明白,現(xiàn)在冷靜下來自己看看,這里也算入門了。委托,說白了就是一種相當(dāng)于c++函數(shù)指針的東東(如果對C++函數(shù)指針不熟的話這就等于白說了啊,還是看下面的例子吧!)~
    首先看一下委托的額聲明例子:
    public void delegate Delete_Delegate(string args);委托的聲明中有兩個東西是非常重要的,第一個是void,也就是這個委托可以注冊(代表)的函數(shù)的返回值,其次便是args,這個是該委托可以注冊(代表)的函數(shù)所使用的參數(shù)。換句話說,所有的以string為參數(shù),以void為返回值(這里暫時這么說)的函數(shù)都是可以通過這個委托進行注冊的!
    我想看到這個大家就應(yīng)該很有感觸了,一個方法,除了方法名,最能標(biāo)志它的東西無非就是返回值和參數(shù),至于修飾符,后面再提,所以委托可以說是抓住了方法的核心成分,置于方法名么,這個自然好理解,如果把方法名也通過委托表現(xiàn)出來,那就不需要委托的存在了,其實后面還有一個用處,那就是多播委托~后面再講

    二、委托的使用
    委托的使用分為三個步驟:1.委托聲明  2.委托注冊  3.委托調(diào)用a. 委托聲明,舉個例子:public void delegate Print(string name);解說同上!

    b. 委托注冊:現(xiàn)在假設(shè)有一個函數(shù):
        public void speakEnglish(string say){
                Console.WriteLine(say);
        }
    注冊方法:Print english = new Print(speakEnglish);
    解說:委托其實可以被看作是一個特殊的類,很明顯,這里聲明的就是該類的實例english,我們再注意一下這里的構(gòu)造函數(shù)所使用的參數(shù),它是一個方法名,該方法必須和委托聲明的方法簽名一致,否則會拋出異常;上面只是一種注冊方式,還有其他便捷的方法~

    c. 委托調(diào)用:english("hello"); 這個時候控制臺便會輸出hello字符,委托調(diào)用成功!


    #########################################華麗麗的分割線#############################################

    以上所描述的是最最基本的委托使用過程,接下來引申開來,繼續(xù)深入

    三、多播委托
    多播委托對于委托實現(xiàn)其價值來說真的是很重要的,比如在事件監(jiān)聽中的使用。
    多播委托的特點:
    1)多播委托,顧名思義,就是說可以通過委托一次調(diào)用一個以上的方法;
    2)多播委托聲明時必須返回void,否則會拋出異常;
    3)多播委托一旦遇到一個函數(shù)拋出異常,則會停止執(zhí)行剩余的函數(shù);(這個是可以解決的)
    這里也可以體會到為什么不需要把方法名通過委托表現(xiàn)出來的原因。

    下面舉一個多播委托的例子:延續(xù)上面的例子(注:多播委托和一般委托的聲明并沒有什么決定性區(qū)別,唯一要注意的就是上面說的特點2)
    假設(shè)還有一個方法:
       
     public void speakChinese(string say){
            Console.WriteLine(say);
        }
    下面需要同時調(diào)用兩個方法,那么怎么通過多播委托實現(xiàn)呢?
        Print print = new Print(speakEnlish);
        print += speakChinese;
        print("Hello, 中國!");
    這樣的話控制臺上就會出現(xiàn)兩邊Hello,中國字符。
    解釋:1)很明顯,多播委托不管注冊多少方法,其方法簽名一致的要求是不可以更改的!
            2)注冊的時候首先聲名委托的實例,然后可以通過“+=”運算符添加(注冊)更多的方法!同理可知,也可以通過運算符“-=”取消注冊;
            3)注冊完畢后,一旦如同一般委托通過委托實例傳入?yún)?shù)則所有注冊過的方法都會接收參數(shù)運行一遍!并且是沒有執(zhí)行順序的!
    通過3)可以解釋為什么返回值必須是void,甚至返回值是同一個類型都不可以!因為多播委托中注冊的方法是一起調(diào)用的,如果有返回值,比如一個返回1,一個返回2,那么就會出現(xiàn)一個函數(shù)(委托)返回多個值的情況,總會出錯!所以必須為Void.

    到這里,我想具體什么是委托,怎么使用委托基本上比較清楚了,下面我最最關(guān)心的就是到底委托會被用在哪些地方呢?委托是C#中比較獨特的一個技術(shù),存在即是真理,它的優(yōu)點在什么地方?(很不幸,我C++沒學(xué)好,關(guān)于C++函數(shù)指針的有點也沒參透,所以不能遷移過來)

    ####################################委托的能力######################################
    大家在使用集合時,一定使用過Sort類似的方法,這個方法就是用來對集合中的元素進行排序的,對于一般元素,比如int等等,它內(nèi)部就嵌有比較方法在里面,然而,很多時候我們需要比較的往往不是這么簡單的東西,很多時候我們要比較的是我們自己定義的類型。而Sort方法中也有一個構(gòu)造函數(shù),是需要我們自己傳入比較函數(shù)的,這里就是一個使用委托的絕佳范例。下面引用的例子來自《C#高級編程(第6版)》(有興趣的話可以去看看,書不錯,就是厚了點)
    程序1:
     1 using System;
     2 using System.Collections.Generic;
     3 using System.Text;
     4 
     5 namespace Wrox.ProCSharp.Delegates
     6 {
     7    class Employee
     8    {
     9       private string name;
    10       private decimal salary;
    11 
    12       public Employee(string name, decimal salary)
    13       {
    14          this.name = name;
    15          this.salary = salary;
    16       }
    17 
    18       public override string ToString()
    19       {
    20          return string.Format("{0}, {1:C}", name, salary);
    21       }
    22 
    23       public static bool CompareSalary(object x, object y)
    24       {
    25          Employee e1 = (Employee)x;
    26          Employee e2 = (Employee)y;
    27          return (e1.salary < e2.salary);
    28       }
    29    }
    30 }
    這個Employee類里面定義了一個比較方法,CompareSalary,這個方法就是等會兒需要注冊委托的方法

    程序2:
     1 using System;
     2 using System.Collections.Generic;
     3 using System.Text;
     4 
     5 namespace Wrox.ProCSharp.Delegates
     6 {
     7    delegate bool Comparison(object x, object y);
     8 
     9    class BubbleSorter
    10    {
    11       static public void Sort(object[] sortArray, Comparison comparer)
    12       {
    13          for (int i = 0; i < sortArray.Length; i++)
    14          {
    15             for (int j = i + 1; j < sortArray.Length; j++)
    16             {
    17                if (comparer(sortArray[j], sortArray[i]))
    18                {
    19                   object temp = sortArray[i];
    20                   sortArray[i] = sortArray[j];
    21                   sortArray[j] = temp;
    22                }
    23             }
    24          }
    25       }
    26    }
    27 }
    這個類里面聲明了一個委托,可以看到這個委托和上面Employee類里面的方法簽名是一樣的,也就是說可以通過這個代理注冊上面的CompareSalary方法

    程序3:
     1 using System;
     2 using System.Collections.Generic;
     3 using System.Text;
     4 
     5 namespace Wrox.ProCSharp.Delegates
     6 {
     7 
     8    class Program
     9    {
    10       static void Main()
    11       {
    12          Employee[] employees =
    13          {
    14            new Employee("Bugs Bunny"20000),
    15            new Employee("Elmer Fudd"10000),
    16            new Employee("Daffy Duck"25000),
    17            new Employee("Wiley Coyote", (decimal)1000000.38),
    18            new Employee("Foghorn Leghorn"23000),
    19            new Employee("RoadRunner'"50000)};
    20 
    21          BubbleSorter.Sort(employees, Employee.CompareSalary);
    22 
    23          foreach (var employee in employees)
    24          {
    25             Console.WriteLine(employee);
    26          }
    27          //for (int i = 0; i < employees.Length; i++)
    28          //   Console.WriteLine(employees[i].ToString());
    29       }
    30    }
    31 }
    我們看一下這里是怎么使用委托的!
    首先聲明了一個Employee數(shù)組,目標(biāo)是對里面的元素盡心排序,我們看到,排序使用的方法是靜態(tài)的Sort()方法,傳入了一個數(shù)組和一個方法名,而在Sort()方法的參數(shù)列表里面大家可以看到,與方法名對應(yīng)的位置是委托的實例,也就是說,我們把比較的方法通過委托傳給了比較函數(shù),這樣,我們就能夠通過改變比較的方法來實現(xiàn)比較我們自己定義的類型的目的!
    個人感覺這樣的實現(xiàn)很方便,尤其是將比較函數(shù)分離出來,這樣符合程序的“開閉原則”,將需要變化,可能變化的部分剝離了出來~~

    當(dāng)然,委托的能力不是這樣一個例子可以說清楚的,況且這里還沒有列出多播委托的例子,在窗體事件中每個多播委托可以實現(xiàn)一個事件激發(fā)多個監(jiān)聽者的功能,所以說到底委托有什么好處,該怎么使用,都需要多多實踐才能更多的領(lǐng)悟~

    接下來還有些東西值得侃一侃:
    1.委托之匿名方法:
    委托不但可以為已經(jīng)存在的方法注冊,而且在編輯過程中可以直接添加一個匿名方法,換句話說,就是臨時寫一個方法放入注冊列表中,下面是一個示例,延續(xù)上面的案例:
       Print print = delegate(string say){
            Console.WriteLine(say);
        }

    這里注冊就不是一個方法了,而是一個代碼塊,關(guān)鍵字是delegate,這是不能更改的,后面的傳入?yún)?shù)以及里面方法的返回值(如果有返回值的情況)必須要和委托聲明的一致!
    這里我有一個疑問,這種匿名方法的委托使用是不是可以用在多播委托中?按常理應(yīng)該是可以添加的,那么怎么取消注冊呢?(沒有方法名的情況下是不可能使用-=的嘛~)

    2.委托
    λ表達式

    λ
    表達式是C#3.0新提供的語法,用于委托類型以簡化代碼,事實上,
    λ
    表達式
    就是委托形式的一種符號表達形式,下面是一個示例:

    上面的匿名方法的例子是可以這么用表達式寫的:
        Print print => (say) {
            Console.WriteLine(say);
        }
    上面的表達式很奇怪吧?say這個變量沒有實現(xiàn)聲明就開始使用了對吧?解釋如下:
    其實say是聲明過的,在哪里聲明的呢?對,沒錯,就是第一次使用的時候聲明的,但是很明顯,這里根本不像變量聲明啊!根本就沒有指出類型嘛,這就是委托的獨特之處,在聲明委托的時候就已經(jīng)指出了參數(shù)的類型,在這里表達式是專門代替委托而存在的,也就相當(dāng)于在這里指出了say的類型!

    下面再看一個例子就知道表達式和委托的關(guān)系了:
    委托聲明:public delegate bool  Predicate(int object);
    看下面的使用方法:
    Predicate p1 = x => x>5;
    list.findAll(
    x => x>5
    );
    第二種使用方式相當(dāng)于:
    list.findAll(
    delegate(int x){return x>5}
    )
    ;
    對比上面兩條語句,是否有所感悟?

    3.委托之協(xié)變與抗變
    這個我想也不太常遇到,其實就是委托的參數(shù)與返回值和父類與子類之間的一種轉(zhuǎn)換,這里就不羅哩羅嗦了~~


    寫寫寫寫發(fā)現(xiàn)有點像是整理,不過想說的也基本上說在這里了,歡迎留下意見,也歡迎留下問題互相交流~




    posted on 2011-09-01 15:30 灰色客棧 閱讀(246) 評論(0)  編輯  收藏


    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     
    <2011年9月>
    28293031123
    45678910
    11121314151617
    18192021222324
    2526272829301
    2345678

    導(dǎo)航

    統(tǒng)計

    常用鏈接

    留言簿

    隨筆檔案

    文章檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 亚洲一区二区女搞男| 亚洲中文无码永久免| 真人做人试看60分钟免费视频| 在线电影你懂的亚洲| 成人免费视频网址| 中文字幕免费在线看| 亚洲福利电影一区二区?| 性做久久久久免费观看| 免费无码av片在线观看| 亚洲 日韩 色 图网站| 国产午夜亚洲不卡| 大地资源二在线观看免费高清| 免费中文字幕视频| 亚洲国产精品白丝在线观看| 亚洲国产V高清在线观看| 日韩免费在线观看视频| 性色av极品无码专区亚洲 | 国产亚洲人成A在线V网站 | 亚洲国产另类久久久精品黑人| av无码免费一区二区三区| 五月天婷婷精品免费视频| 亚洲欧洲综合在线| 国产成人亚洲精品影院| 无码国产精品久久一区免费| 岛国精品一区免费视频在线观看| 亚洲熟女www一区二区三区| 亚洲第一AV网站| 亚洲精品A在线观看| 青苹果乐园免费高清在线| 在线人成免费视频69国产| 国产精品亚洲а∨天堂2021 | 免费日本黄色网址| 成人免费一级毛片在线播放视频| 中文字幕无线码中文字幕免费| 自拍偷区亚洲国内自拍| 亚洲色图古典武侠| 亚洲国产精品久久| 国产亚洲一区二区三区在线| 亚洲av日韩av欧v在线天堂| 在线观看成人免费视频| 在线视频观看免费视频18|