一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

.NET中的委托:細(xì)節(jié)詳解-IT168 技術(shù)開發(fā)專區(qū)

 遙遠(yuǎn)的橋zz 2011-04-27
【IT168 技術(shù)】委托是一種引用方法的類型。一旦為委托分配了方法,委托將與該方法具有完全相同的行為。委托方法的使用可以像其他任何方法一樣,具有參數(shù)和返回值,如下面的示例所示:

  1 .定義 

//Code in C#

  
public delegate int PerformCalculation(int x, int y);

  與委托的簽名(由返回類型和參數(shù)組成)匹配的任何方法都可以分配給該委托。

  簡(jiǎn)單理解Delegate委托(或代理)是一種數(shù)據(jù)類型:它的變量可以引用到某一個(gè)符合要求的方法上,通過(guò)委托可以間接地調(diào)用該方法。

  其實(shí).NET的委托類似于C語(yǔ)言的函數(shù)指針,區(qū)別在于.NET委托是類型安全的,這說(shuō)明,C中的函數(shù)指針只不過(guò)是一個(gè)指向存儲(chǔ)單元的指針,我們無(wú)法說(shuō)出這個(gè)指針實(shí)際指向什么。

    2. 委托使用

  使用委托的四部曲:

  定義一種委托類型

  委托執(zhí)行時(shí)要調(diào)用方法

  定義一個(gè)委托實(shí)例

  委托實(shí)例的調(diào)用

  我們先定義一種委托類型如下:

//自定義一種委托類型
publicdelegatevoid StringProcessor(string input);
然后我們?cè)俣x5中候選的委托方法如下:
void PrintString(string x)
void PrintInteger(int x)
void PrintTwoStrings(string x, string y) int GetStringLength(string x)
void PrintObject(object x)

  大家猜猜看哪個(gè)和上面提供的委托類型簽名匹配(簽名匹配:參數(shù)類型,參數(shù)個(gè)數(shù)和返回類型匹配)。激動(dòng)時(shí)刻到了馬上公布答案,和委托類型匹配的方法是PrintString和PrintObject,如果有不明白的請(qǐng)細(xì)細(xì)考慮一下委托匹配的條件—簽名匹配。

  

                                                          圖1委托成功輸出

  現(xiàn)在對(duì)委托有了一定的認(rèn)識(shí),接下來(lái)我們將介紹委托最經(jīng)常使用的地方—事件。

  我們將從發(fā)送器和接受器的角度討論事件,例如在UI編程中,鼠標(biāo)單擊或鍵盤按鍵,發(fā)送器就是.NET的CLR,注意事件發(fā)送器并不知道接收器是誰(shuí),這符合面向?qū)ο蟮脑瓌t,而且某個(gè)事件接收器有個(gè)方法處理該事件,這個(gè)時(shí)候就要委托,如前面所講事件發(fā)送器對(duì)事件接收器一無(wú)所知,通過(guò)委托作為一個(gè)中介,接收器把事件處理方法注冊(cè)到事件中,這樣就實(shí)現(xiàn)了由發(fā)送器->委托->接收器的過(guò)程了。

  我們可以這樣認(rèn)為:委托是一個(gè)類,它定義了方法的類型,使得可以將方法當(dāng)作另一個(gè)方法的參數(shù)來(lái)進(jìn)行傳遞,這種將方法動(dòng)態(tài)地賦給參數(shù)的做法,可以避免在程序中大量使用If-Else(Switch)語(yǔ)句,同時(shí)使得程序具有更好的可擴(kuò)展性。

        


   3 .自定義委托

  前面話有點(diǎn)難以理解,接下來(lái)我們通過(guò)具體的例子分析一下何謂委托,該如何實(shí)現(xiàn)委托?,F(xiàn)在不是很喜歡搞多國(guó)語(yǔ)言化的嗎?看看如何讓我們的程序會(huì)說(shuō)多種語(yǔ)言吧! 

/// <summary>
        
/// the English speaker.
        
/// </summary>
        
/// <param name="name">The name.</param>
        
public void EnglishSpeaker(string name)
        {
            Console.WriteLine(
                
string.Format("Hello my name is {0} and I am English speaker.\n", name));
        }

        
/// <summary>
        
/// the Chineses speaker.
        
/// </summary>
        
public void ChineseSpeaker(string name)
        {
            Console.WriteLine(
                
string.Format("您好我的名字叫{0},我是講普通話的。\n", name));
        }

    好啦現(xiàn)在我們有兩個(gè)方法分別是說(shuō)普通話和英語(yǔ),現(xiàn)在我們的程序會(huì)說(shuō)普通話和英語(yǔ)啦?,F(xiàn)在我們考慮究竟什么時(shí)候講普通話什么時(shí)候講英語(yǔ),那不簡(jiǎn)單我們加個(gè)判斷就OK啦,是的我們可以通過(guò)switch或者if else就可以實(shí)現(xiàn)啦。  

/// <summary>
        
/// 根據(jù)上下文調(diào)用不同的方法
          
/// </summary>
        
/// <param name="name">string</param>
        
/// <param name="lang">enum</param>
        
private static void Say(string name, Language lang)
        {
            switch (lang)
            {
                
case Language.Chinese:
                    Program.ChineseSpeaker(name);
                    break;
                
case Language.English:
                    Program.EnglishSpeaker(name);
                    break;
                default :
                    break;
            }
        }

   但假設(shè)我們現(xiàn)在又要增加新的語(yǔ)言西班牙語(yǔ),同樣我們可以增加西班牙語(yǔ),但我們必須修改switch語(yǔ)句增加判斷,這不符合OOP中的OCP(對(duì)擴(kuò)展開放,對(duì)修改關(guān)閉原則),這時(shí)候委托該登場(chǎng)

。/// <summary>
        
/// Define speak delegate.
        
/// </summary>
        
/// <param name="name"></param>
        
private delegate void SpeakDelegate(string name);

    首先我們定義了一種委托類型SpeakDelegate,然后我們通過(guò)修改Say方法看看該如何使用委托變量

。/// <summary>
        
/// The base say function.
        
/// </summary>
        
/// <param name="name">The name.</param>
        
/// <param name="speaker">The speaker.</param>
        
private static void Say(string name, SpeakDelegate speaker)
        {
            
///Inoke the speaker function.
            speaker(name);
        }

    現(xiàn)在我們的參數(shù)已經(jīng)不是枚舉類型了,而是一個(gè)委托類型變量,而且實(shí)現(xiàn)的具體代碼也沒(méi)有了switch語(yǔ)句了,比之前簡(jiǎn)單了許多。現(xiàn)在大家知道如何去調(diào)用Say方法吧!沒(méi)錯(cuò)我們只需傳遞一個(gè)name和一個(gè)具體實(shí)現(xiàn)函數(shù)名就OK了。    

///傳遞函數(shù)名進(jìn)行委托方法綁定
                       Program.Say(
"鈞航", ChineseSpeaker);
           Program.Say(
"JK.Rush", EnglishSpeaker);

 自定義委托相信大家都會(huì)了,接下來(lái)我將介紹一下.NET中委托實(shí)現(xiàn),由于許多使用委托的例子都是事件,所以下面的例子也采用事件。但請(qǐng)大家要注意“可以使用委托,但卻沒(méi)有定義事件”的情況(例如:回調(diào)函數(shù))。


       4 .NET中的事件委托

  舉一個(gè)簡(jiǎn)單的例子,.NET中經(jīng)常使用的控件Button,當(dāng)我們把Button 控件 drap and drop到界面,然后雙擊界面的Button我們發(fā)現(xiàn)程序中自動(dòng)生成了一個(gè)響應(yīng)Button的事件方法,然后我們給事件方法添加Code之后,當(dāng)我們點(diǎn)擊該Button就響應(yīng)該方法了,但我們沒(méi)有看到代碼中有任何的委托和事件之類的定義,其實(shí)這些.NET都已經(jīng)做好了。我們可以查看如下文件。

  

  

                                                                     圖2事件委托實(shí)現(xiàn)

  如上圖所示我們打開Designer文件,事件委托的實(shí)現(xiàn)都在這里實(shí)現(xiàn)了。

  其中,EventHandler就是一個(gè)代理類型,可以認(rèn)為它是一個(gè)“類”,是所有返回類型為void,具備兩個(gè)參數(shù)分別是object sender和EventArgs e,第一個(gè)參數(shù)表示引發(fā)事件的控件,或者說(shuō)它表示點(diǎn)擊的那個(gè)按鈕。通過(guò)以下的代碼我們細(xì)細(xì)解析一下。

   

private void button1_Click(object sender, EventArgs e)
        {
            
//獲取被點(diǎn)擊Button的實(shí)例
            Button objBotton
= sender as Button;
            
if (objBotton != null)
            {
                objBotton.Text
= "Hello you click me.";
                objBotton.AutoSize
= true;
            }
            
else
            {
                
//Exception Handle.
            }

     

  

                             圖3點(diǎn)擊產(chǎn)生效果

  OK現(xiàn)在明白了sender就是傳遞一個(gè)被點(diǎn)擊對(duì)象的實(shí)例,第二個(gè)參數(shù)名叫e的EventArgs參數(shù),用于 表示附加的事件關(guān)聯(lián)的事件信息。當(dāng)點(diǎn)擊按鈕時(shí),沒(méi)有附加任何關(guān)聯(lián)的事件信息,如上的點(diǎn)擊事件,第二參數(shù)并不表示任何有用的信息。但什么時(shí)候會(huì)用到呢?

  我們先介紹一下EventArgs這個(gè)的類型。其實(shí)這個(gè)類并沒(méi)有太多的功能,它主要是作為一個(gè)基類讓其他類去實(shí)現(xiàn)具體的功能和定義,當(dāng)我們搜索EventArgs發(fā)現(xiàn)很多類是繼承于它的。

public class EventArgs
{   
             // Fields   
             public static readonly EventArgs Empty;    
            // Methods    static EventArgs();    
             public EventArgs();}

 

    舉其中的ImageClickEventArgs為例,它繼承于EventArgs,而且還添加了自己的字段用來(lái)基類X和Y的坐標(biāo)值(這是一個(gè)ImageButton被點(diǎn)擊時(shí)候響應(yīng)的),然后獲取該按鈕的X和Y坐標(biāo)。

   

                      圖4獲取ImageClickEventArgs關(guān)聯(lián)點(diǎn)擊坐標(biāo)

  前面提到其他事件關(guān)聯(lián)信息類型都是通過(guò)繼承EventArgs實(shí)現(xiàn)的,所以說(shuō)我們自己也可以自定義一個(gè)事件關(guān)聯(lián)信息類型,如下我們只需繼承EventArgs就OK了。 

/// <summary>
    
/// 自定義事件關(guān)聯(lián)類
    
/// </summary>
    
public class ColorChangedEventArgs : EventArgs
    {
        
private Color color;

        
/// <summary>
        
/// Initializes a new instance of the <see cref="ColorChangedEventArgs"/> class.
        
/// </summary>
        
/// <param name="c">The c.</param>
        
public ColorChangedEventArgs(Color c)
        {
            color
= c;
        }

        
/// <summary>
        
/// Gets the color of the get.
        
/// </summary>
        
/// <value>
        
/// The color of the get.
        
/// </value>
        
public Color GetColor
        {
            
get { return color; }
        }

}

       5.自定義事件委托

  多播委托

  前面使用的每個(gè)委托都只包含一個(gè)方法調(diào)用。調(diào)用一個(gè)委托就調(diào)用一個(gè)方法調(diào)用。如果要通過(guò)一個(gè)委托調(diào)用多個(gè)方法,那就需要使用委托的多播特性。如果調(diào)用多播委托,就可以按委托添加次序連續(xù)調(diào)用多個(gè)方法。為此,委托的簽名就必須返回void;否則,就只能得到委托調(diào)用的最后一個(gè)方法的結(jié)果,接下來(lái)看看多播實(shí)現(xiàn)。

 

namespace Multi_Delegate
{
    delegate void StringProcessor();
    
public class Person
    {
        
private string _Name;
        
public Person(string name)
        {
            this._Name
= name;
        }

        
public void Say()
        {
            Console.WriteLine(
"Hello my name is {0}, what's your name.\n", this._Name);
        }

        
public void Reply()
        {
            Console.WriteLine(
"Hello my name is {0} and nice to meet you.\n", this._Name);
        }
    }

    class Program
    {
        static void Main(
string[] args)
        {
            Person Jack
= new Person("Jack");
            Person Oliver
= new Person("Oliver");
            StringProcessor sp
= null;
//綁定多播方法調(diào)用
            sp
+= Jack.Say;
            sp
+= Oliver.Reply;
            sp();
            Console.ReadKey();
        }
    }
}

    也許有人覺得很簡(jiǎn)單,實(shí)現(xiàn)的確簡(jiǎn)單明了,就是通過(guò)“+”把方法調(diào)用綁定到委托變量中,如果我們用“-”就可以移除綁定到委托變量方法了。

  事件

  前面一直沒(méi)有解釋什么是事件,現(xiàn)在讓我用一句話解釋事件和委托的關(guān)系吧!

  事件和委托關(guān)系就像是屬性和字段的關(guān)系,為了剛好的實(shí)現(xiàn)OOP的編程原則,事件對(duì)委托進(jìn)行了封裝。

  現(xiàn)在我們修改前面的代碼,使用事件對(duì)委托進(jìn)行封裝。

 /// 使用事件對(duì)委托進(jìn)行封裝
    
/// </summary>
    
public class Say
    {
        
/// <summary>
        
/// 封裝委托字段
        
/// </summary>
        
public static event SpeakDelegate speakDelegate;
        
        
/// <summary>
        
/// 調(diào)用委托具體實(shí)現(xiàn)方法
        
/// </summary>
        
/// <param name="name"></param>
        
public static void SayManager(string name)
        {
            speakDelegate(name);
        }
    }


        
/// <summary>
        
/// 客戶端調(diào)用委托
        
/// </summary>
        
/// <param name="args"></param>
        static void Main(
string[] args)
        {
            Say.speakDelegate
+= Program.ChineseSpeaker;
            Say.speakDelegate
+= Program.EnglishSpeaker;
            Say.SayManager(
"Jackson");
            Console.ReadKey();

 

   

                                                             圖5自定義委托

  現(xiàn)在讓我們看看編譯后Say類就可以充分證明我們的結(jié)論:事件是對(duì)委托封裝。

  

                                         圖6自定義事件編譯后的代碼

  大家看到在編譯后的代碼中出現(xiàn)了一個(gè)私有的委托變量,然后接下是一個(gè)公用事件委托變量,這進(jìn)一步說(shuō)明了事件是對(duì)委托的封裝。

  

                                               圖7自定義事件編譯后MSIL代碼


       6.事件委托實(shí)現(xiàn)觀察者模式

  前面我們介紹按鈕事件響應(yīng)是從發(fā)送者和接收者的角度出發(fā)的,現(xiàn)在我們以設(shè)計(jì)模式中的觀察者模式為例。

  

                                                   圖8GoF觀察者架構(gòu) 

/// 使用事件對(duì)委托進(jìn)行封裝
    
/// </summary>
    
public class Say
    {
        
/// <summary>
        
/// 封裝委托字段
        
/// </summary>
        
public static event SpeakDelegate speakDelegate;
        
        
/// <summary>
        
/// 調(diào)用委托具體實(shí)現(xiàn)方法
        
/// </summary>
        
/// <param name="name"></param>
        
public static void SayManager(string name)
        {
            speakDelegate(name);
        }
    }


        
/// <summary>
        
/// 客戶端調(diào)用委托
        
/// </summary>
        
/// <param name="args"></param>
        static void Main(
string[] args)
        {
            Say.speakDelegate
+= Program.ChineseSpeaker;
            Say.speakDelegate
+= Program.EnglishSpeaker;
            Say.SayManager(
"Jackson");
            Console.ReadKey();

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    深夜视频在线观看免费你懂| 中文字幕乱码一区二区三区四区| 久久国产亚洲精品赲碰热| 国产一区二区精品丝袜| 激情中文字幕在线观看 | 91久久精品国产一区蜜臀| 91日韩在线观看你懂的| 天堂网中文字幕在线视频| 国产精品免费自拍视频| 国产欧美高清精品一区| 欧美中文字幕一区在线| 黄色片一区二区在线观看| 亚洲国产成人精品福利| 中文字幕欧美视频二区| 欧美一级特黄大片做受大屁股| 亚洲一区二区精品免费视频| 果冻传媒精选麻豆白晶晶 | 日韩一区二区三区嘿嘿| 国产精品免费视频久久| 少妇一区二区三区精品| 富婆又大又白又丰满又紧又硬| 黄色片一区二区在线观看| 超薄肉色丝袜脚一区二区| 亚洲中文字幕人妻系列| 午夜福利在线观看免费| 中文字幕久热精品视频在线 | 色丁香之五月婷婷开心| 在线观看视频日韩精品| 亚洲欧美日韩综合在线成成| 久热青青草视频在线观看| 欧美日韩国产综合在线| 欧美一级日韩中文字幕| 久久精品视频就在久久| 99久久免费中文字幕| 在线观看免费无遮挡大尺度视频 | 日本高清不卡在线一区| 国产精品久久熟女吞精| 色偷偷亚洲女人天堂观看| 日韩特级黄片免费在线观看| 99香蕉精品视频国产版| 亚洲中文字幕免费人妻|