国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

[CLR via C#]17. 委托

2019-11-17 03:19:44
字體:
供稿:網(wǎng)友

[CLR via C#]17. 委托

回調(diào)函數(shù)是一種非常有用的編程機(jī)制,它已經(jīng)存在很多年了。Microsoft .NET Framework通過委托(delegate)來提供一種回調(diào)機(jī)制。不同于其他平臺(tái)(比如非托管C++)的回調(diào)機(jī)制,委托提供了多得多的功能。例如,委托確?;卣{(diào)方法是類型安全的(這是CLR最重要的目標(biāo)之一)。委托還允許順序調(diào)用多個(gè)方法,并支持調(diào)用靜態(tài)方法和實(shí)例方法。一、初識(shí)委托為了理解委托,先看看如何使用它。委托4個(gè)最基本的步驟:1)定義委托類型2)有一個(gè)方法包含要執(zhí)行的代碼3)創(chuàng)建一個(gè)委托實(shí)例化(包含聲明委托對(duì)象)4)執(zhí)行調(diào)用(invoke)委托實(shí)例具體解釋如下:1.定義委托類型委托類型就是參數(shù)類型的一個(gè)列表以及一個(gè)返回類型。
delegate void StringPRocessor(string input);

其中的StringProcessor是一個(gè)類型。

2.定義簽名相同的方法定義的方法要與委托有類型相同的返回值和參數(shù)。
private void GetStringLength(object x){}  //C#2.0以后認(rèn)為一致

  3.創(chuàng)建委托實(shí)例

  創(chuàng)建委托實(shí)例就是指定在調(diào)用委托實(shí)例時(shí)執(zhí)行的方法。
StringProcessor proc1,proc2//GetStringLength 實(shí)例方法proc1= new StringProcessor(GetStringLength);//GetString 靜態(tài)方法proc2 += GetString;

  

  4.調(diào)用委托  調(diào)用委托就是調(diào)用一個(gè)委托實(shí)例方法?! ?pre>proc1("Hello World");

  具體的示例代碼:

namespace Program {    //定義委托    delegate void StringProcessor(string input);     class Person    {        string name;        public Person(string name)        {            this.name = name;        }         //定義與委托簽名相同的"方法"        public void Say(string message)        {            Console.WriteLine(name+" say:" + message);        }    }     class BackGround    {        //定義與委托簽名相同的"靜態(tài)方法"        public static void Note(string note)        {            Console.Write("{0}", note);        }    }     class Program    {        static void Main(string[] args)        {            Person jon = new Person("Jom");            Person tom = new Person("Tom");            //創(chuàng)建委托實(shí)例(第一步)            StringProcessor proc1, proc2, proc3;             //創(chuàng)建委托實(shí)例:賦值(第二部)            proc1 = new StringProcessor(jon.Say);            proc2 = new StringProcessor(tom.Say);            proc3 = BackGround.Note;             //調(diào)用委托            proc1("Hello jon");            proc2("Hello tom");            proc3("note");             Console.ReadKey();        }    }}

  書中的代碼示例:
namespace Test{    // 1.聲明委托類型    internal delegate void Feedback(Int32 value);     internal class Program    {        private static void Main(string[] args)        {            StaticDelegateDemo();            InstanceDelegateDemo();            ChainDelegateDemo1(new Program());            ChainDelegateDemo2(new Program());         }         private static void StaticDelegateDemo()        {            Console.WriteLine("----- Static Delegate Demo -----");            Counter(1, 3, null);            // 3.創(chuàng)建委托實(shí)例            Counter(1, 3, new Feedback(Program.FeedbackToConsole));            Counter(1, 3, new Feedback(FeedbackToMsgBox));            Console.WriteLine();        }         private static void InstanceDelegateDemo()        {            Console.WriteLine("----- Instance Delegate Demo -----");            Program di = new Program();            // 3.創(chuàng)建委托實(shí)例            Counter(1, 3, new Feedback(di.FeedbackToFile));             Console.WriteLine();        }         private static void ChainDelegateDemo1(Program di)        {            Console.WriteLine("----- Chain Delegate Demo 1 -----");            // 3.創(chuàng)建委托實(shí)例            Feedback fb1 = new Feedback(FeedbackToConsole);            Feedback fb2 = new Feedback(FeedbackToMsgBox);            Feedback fb3 = new Feedback(di.FeedbackToFile);             Feedback fbChain = null;            fbChain = (Feedback)Delegate.Combine(fbChain, fb1);            fbChain = (Feedback)Delegate.Combine(fbChain, fb2);            fbChain = (Feedback)Delegate.Combine(fbChain, fb3);            Counter(1, 2, fbChain);             Console.WriteLine();            fbChain = (Feedback)Delegate.Remove(fbChain, new Feedback(FeedbackToMsgBox));            Counter(1, 2, fbChain);        }         private static void ChainDelegateDemo2(Program di)        {            Console.WriteLine("----- Chain Delegate Demo 2 -----");            Feedback fb1 = new Feedback(FeedbackToConsole);            Feedback fb2 = new Feedback(FeedbackToMsgBox);            Feedback fb3 = new Feedback(di.FeedbackToFile);             Feedback fbChain = null;            fbChain += fb1;            fbChain += fb2;            fbChain += fb3;            Counter(1, 2, fbChain);             Console.WriteLine();            fbChain -= new Feedback(FeedbackToMsgBox);            Counter(1, 2, fbChain);        }         private static void Counter(Int32 from, Int32 to, Feedback fb)        {            for (Int32 val = from; val <= to; val++)            {                // 如果指定了任何回調(diào),就可以調(diào)用它                if (fb != null)                    // 4.調(diào)用委托                    fb(val);            }        }         // 2.聲明簽名相同的方法        private static void FeedbackToConsole(Int32 value)        {            Console.WriteLine("Item=" + value);        }         // 2.聲明簽名相同的方法        private static void FeedbackToMsgBox(Int32 value)        {            Console.WriteLine("Item=" + value);        }         // 2.聲明簽名相同的方法        private void FeedbackToFile(Int32 value)        {            StreamWriter sw = new StreamWriter("Status", true);            sw.WriteLine("Item=" + value);            sw.Close();        }    }}

二、用委托回調(diào)靜態(tài)方法在上面的代碼中,我們可以清楚的看到用委托如何回調(diào)靜態(tài)方法。直接將靜態(tài)方法綁定到委托的實(shí)例上,再通過實(shí)例進(jìn)行調(diào)用。將一個(gè)方法綁定到一個(gè)委托時(shí),C#和CLR都允許引用類型的協(xié)變性和逆變性。協(xié)變性是指方法能返回從委托的返回類型派生的一個(gè)類型。逆變性是指方法獲取的參數(shù)可以是委托的參數(shù)類型的基類。例如下面的委托:
deleget Object MyCallback(FileStream s);

完全可以構(gòu)造該委托類型的一個(gè)實(shí)例,并和具有一下原型的一個(gè)方法綁定:

String SomeMethod(Stream s);

在這里,SomeMethod的返回類型(String)派生自委托的返回類型(Object);這種協(xié)變性是允許的。SomeMethod的參數(shù)類型(Stream)是委托的參數(shù)類型(FileStream)的基類;這種逆變性是運(yùn)行部的。

注意,協(xié)變性和逆變性只能用于引用類型,不能作用于值類型和void。所以下面示例是錯(cuò)誤的:
Int32 SomeMethod(Stream s);//這是錯(cuò)誤的

值類型和void之所以不支持協(xié)變性和逆變性,是因?yàn)樗鼈兊拇鎯?chǔ)結(jié)構(gòu)是變化的,而引用類型的存儲(chǔ)結(jié)構(gòu)始終是一個(gè)指針。

三、用委托回調(diào)實(shí)例方法使用委托回調(diào)實(shí)例方法,在上面代碼中演示已經(jīng)非常清楚了,就不細(xì)說了。四、委托揭秘從表面看,委托似乎很容易使用:用C#的delegate關(guān)鍵字聲明,用熟悉的new操作符構(gòu)造委托實(shí)例,用熟悉的方法調(diào)用語法來調(diào)用回調(diào)函數(shù)。然而,實(shí)際情況遠(yuǎn)比前面例子演示的復(fù)雜的多。編譯器和CLR在幕后做了大量工作來隱藏復(fù)雜性。本節(jié)重點(diǎn)講解了編譯器和CLR如何協(xié)同工作來實(shí)現(xiàn)委托。首先讓我們重寫審視下面的代碼:
internal delegate void Feedback(Int32 value);

  看到這行代碼,編譯器實(shí)際會(huì)像下面這樣定義一個(gè)完整的類:

internal class Feedback: System.MulticastDelegate {    // 構(gòu)造器    public Feedback(Object object, IntPtr method);     // 這個(gè)方法和源代碼指定的原型一樣    public virtual void Invoke(Int32 value);     // 以下方法實(shí)現(xiàn)了對(duì)回調(diào)方法的異步回調(diào)    public virtual IAsyncResult BeginInvoke(Int32 value, AsyncCallback callback, Object object);    public virtual void EndInvoke(IAsyncResult result);}

  編譯器定義的類有4個(gè)方法:一個(gè)構(gòu)造器、Invoke、BeginInvoke和EndInvoke。本節(jié)重點(diǎn)解釋構(gòu)造器和Invoke,BeginInvoke和EndInvoke看留到后面講解。

  事實(shí)上,可用ILDasm.exe查看生成的程序集,驗(yàn)證編譯器真的會(huì)自動(dòng)生成這個(gè)類,如圖17-1所示:  在這個(gè)例子中,編譯器定義了一個(gè)名為Feedback的類,該類派生自FCL定義的System.MulticastDelegate類型(所有委托類型都派生自System.MulticastDelegate類型)?! √崾荆篠ystem.MulticastDelegate類派生自System.Delegate,后則又派生自System.Object。之所以有兩個(gè)委托類,是有歷史原因的?! 膱D中可知Feedback的可訪問性是private,因?yàn)槲性谠创a中聲明為internal類。如果源代碼改成使用public可見性,編譯器生成的類也會(huì)是public類。要注意,委托類即可嵌套在一個(gè)類型中定義,也可以在全局范圍中定義。簡(jiǎn)單地說,由于委托是類,所以凡是能夠定義類的地方,都能定義委托?! ∮捎谒形蓄愋投寂缮訫ulticastDelegate,所以它們繼承了MulticastDelegate的字段、屬性和方法。在這些成員中,有三個(gè)非公共字段是最重要的?! ?table style="width: 100%;" border="1" cellpadding="1">字段類型說明_targetSystem.Object當(dāng)委托對(duì)象包裝一個(gè)靜態(tài)方法時(shí),這個(gè)字段為null。當(dāng)委托對(duì)象包裝一個(gè)實(shí)例方法時(shí),這個(gè)字段引用的是回調(diào)方法要操作的對(duì)象。換言之,這個(gè)字段指出了要傳給實(shí)例方法的隱式參數(shù)this的值_methodPtrSystem.IntPtr一個(gè)內(nèi)部的整數(shù)值,CLR用它來標(biāo)識(shí)要回調(diào)的方法_invocationListSystem.Object該字段通常為null。構(gòu)造一個(gè)委托鏈時(shí),它可以引用一個(gè)委托數(shù)組。  注意,所有委托都有一個(gè)構(gòu)造器,它要獲取兩個(gè)參數(shù):一個(gè)是對(duì)象引用,另一個(gè)是引用回調(diào)方法的一個(gè)整數(shù)。然而,如果仔細(xì)看下簽名的源代碼,會(huì)發(fā)現(xiàn)傳遞的是Program.FeedbackToConsole和di.FeedbackToFile這樣的值,這似乎不可能通過編譯吧?然而,C#編譯器知道要構(gòu)造的是委托,所以會(huì)分析源代碼來確定引用的是哪個(gè)對(duì)象和方法。對(duì)象引用被傳給構(gòu)造器的object參數(shù),標(biāo)識(shí)了方法的一個(gè)特殊IntPtr值(從MethodDef或MemberRef元數(shù)據(jù)token獲得)被傳給構(gòu)造器的method參數(shù)。對(duì)于靜態(tài)方法,會(huì)為object參數(shù)傳遞null值。在構(gòu)造器內(nèi)部,這兩個(gè)實(shí)參分別保存在_target和_methodPtr私有字段中。除此之外,構(gòu)造器還將_invocationList字段設(shè)為null,對(duì)這個(gè)字段的討論推遲到后面。  所以,每個(gè)委托對(duì)象實(shí)際都是一個(gè)包裝器,其中包裝了一個(gè)方法和調(diào)用該方法時(shí)要操作的一個(gè)對(duì)象。例如,在執(zhí)行以下兩行代碼之后:
    Feedback fbStatic = new Feedback(Program.FeedbackToConsole)
發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 武安市| 图木舒克市| 清河县| 富宁县| 聂荣县| 泾川县| 余干县| 大理市| 台湾省| 鹤庆县| 阿克陶县| 襄城县| 舞阳县| 扎兰屯市| 神池县| 道孚县| 绩溪县| 肥城市| 视频| 嘉义市| 通辽市| 巴东县| 苍南县| 湖北省| 玛纳斯县| 乌兰浩特市| 凤山县| 富宁县| 黑龙江省| 漳平市| 东宁县| 扎鲁特旗| 灵台县| 松滋市| 盈江县| 垦利县| 沅江市| 北流市| 天峨县| 岳池县| 富顺县|