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">
注意,所有委托都有一個(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)
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注