日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

C#委托与事件学习笔记

發布時間:2025/4/14 C# 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C#委托与事件学习笔记 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

????? 今天跟隨視頻學習了一下C#中最重要的一些概念之委托與事件。老楊的視頻講的還是挺深入淺出,不過剛接觸C#.NET的人還是朦朦朧朧,就像張子陽先生說的“每次見到委托和事件就覺得心里別(biè)得慌,混身不自在”。跨過這道坎的人就有種一覽眾山小的感覺了。我又瀏覽了皺華棟老師JamesZou的博文《深入理解C#委托及原理》(地址:http://www.cnblogs.com/jameszou/archive/2011/07/21/2112497.html),以及張子陽Jimmy Zhang的博文《C# 中的委托和事件》(地址:http://www.cnblogs.com/jimmyzhang/archive/2007/09/23/903360.html)總算對委托有了一點理性的感覺了,在此謝謝ITCAST,JamesZou以及Jimmmy Zhang的博文,謝謝。

1.委托是神馬?

  用最通俗易懂的話來講,你就可以把委托看成是用來執行方法(函數)的一個“指針”。用鄒老師的一個舉例:“設想,如果我們寫了一個廚師做菜方法用來做菜,里面有拿菜、切菜、配菜、炒菜?四個環節,但編寫此方法代碼的人想讓配菜這個環節讓調用方法的人實現,換句話說,就是想在方法被調用時接收代碼?作為參數,在方法中執行這端傳進來的代碼。但,怎么為一個方法傳?代碼?進來呢?當然大家想到了傳遞接口方式來實現,咱先不討論接口,因為微軟為我們提供了一個叫做委托的類型。”

  現在來看看怎樣使用委托,根據itcast的ppt內容:

  聲明委托的方式:delegate 返回值類型 委托類型名(參數) 比如delegate void StringProcess(string s); 注意這里的除了前面的delegate,剩下部分和聲明一個函數一樣,但是StringProcess不是函數名,而是委托類型名
  聲明的委托是一種類型,就像int、Person一樣,如果要用的話還要聲明委托類型的變量,聲明委托類型變量的方式:StringProcess f1;
  將委托類型變量指向函數 StringProcess sp = new StringProcess(SayHello),這樣就可以像調用普通函數一樣把sp當成函數用了。委托可以看做是函數的指針。整數可以用整數變量指向它,對象可以用對象變量指向它,函數也可以用委托變量指向它。和直接調用函數的區別:用委托就可以指向任意的函數,哪怕是之前沒定義的都可以,而不使用受限于那幾種。
  將委托類型變量指向函數還可以簡化成StringProcess sp = SayHello,編譯器幫我們進行了new。但是不能sp=PrintIt(),因為這樣就成了“執行PrintIt函數,并且將sp指向PrintIt的返回值”。

  這里看一個數據過濾的例子,輸出int數組中的正整數:

  1.聲明一個委托:delegate bool FilterDelegate(int i);

  2.封裝一個過濾的靜態方法,參數中包含一個過濾器的方法委托,返回泛型List<int>列表:

  static List<int> Filter(List<int> list,FilterDelegate fd)
??????? {
??????????? List<int> listTest = new List<int>();
??????????? foreach(int i in list)
??????????? {
??????????????? if(fd(i))
??????????????? {
??????????????????? listTest.Add(i);
??????????????? }
??????????? }
??????????? return listTest;
??????? }

  3.寫一個判斷是否為正整數的方法,返回值為bool類型:

  ???static bool isZhengshu(int i)
??????? {
??????????? return i > 0;
??????? }

  4.在main函數中聲明一個List列表,然后添加部分測試數據,將委托指向判斷正整數的方法,最后遍歷輸出過濾后的數組數據;

  List<int> listOne = new List<int>();
??????listOne.Add(1);
??????listOne.Add(-4);
??????listOne.Add(8);
????? listOne.Add(-6);
????? listOne.Add(13);

??????FilterDelegate fd = isZhengshu;
??????List<int> listResult = Filter(listOne, isZhengshu);
??????foreach (int i in listResult)
??????{
???????????Console.WriteLine(i);
??????} 

  運行后,顯示:1 8 13 

  通過一個小例子,可以得出一個小結論:C#?中的委托類似于?C??C++?中的函數指針。使用委托使程序員可以將方法引用封裝在委托對象內。然后調用該委托對象就可以執行委托對象內方法引用指向的方法,而不必在編譯時知道將調用哪個方法(如參數為委托類型的方法,也就是提供了為程序回調指定方法的機制)。”摘錄自MSDN;

  鄒老師的通俗說法是:“就是一個能存放很多方法的指針的調用清單(但方法簽名必須和委托類型簽名一樣),你一調用這個清單,那么清單里的所有的指針所對應的方法就會依次被執行。

  而委托的原理是神馬?這里就需要跟隨鄒老師的博文走走了,通過VS中自帶的MSIL反編譯程序,將生成后的.exe拖到工具中查看委托類型聲明的代碼,發現其編譯前就生成了一個類;它繼承了System.MulticastDelegate包含了構造方法、BeginInvokeEndInvokeInvoke方法。另外MulticastDelegate則繼承自Delegate類。通過Reflector反編譯工具,可以看出:繼承關系:編譯前生成的類?–>?MulticastDelegate–>?Delegate,而MulticastDelegate類中有3個重要的成員,其中兩個繼承自?Delegate:??

?

  

  

?

  這三者的作用分別是:

  _methodPtr?里保存的就是?方法指針。

  _target?里用來保存方法所在的對象。

  _invocationList?其實使用時是個object數組,在注冊多個方法時,其他方法就保存在此成員中,而它也就是?委托鏈?的關鍵容器。--摘自鄒老師的博文;

2.事件閃亮出場 

  下面來看一個通過委托實現打招呼Greeting的例子(感謝張子陽先生的博文,此例選自其博文)

  1.兩種不同的Greeting方式:

   static void ChineseGreeting(string name)
??????? {
??????????? Console.WriteLine("早上好,"+name);
??????? }

??????? static void EnglishGreeting(string name)
??????? {
??????????? Console.WriteLine("Morning,"+name);
??????? }

  2.聲明一個委托:

  public delegate void GreetingDelegate(string name);

  3.封裝一個類,其中包含一個事件:

  public class GreetingManager
??? {
??????? public GreetingDelegate onGreeting;

??????? public void ProcessGreeting(string name)
??????? {
??????????? if (onGreeting != null)
??????????? {
??????????????? onGreeting(name);
??????????? }
??????? }
??? }

  4.客戶端調用:

  GreetingManager gm = new GreetingManager();
??????gm.onGreeting += EnglishGreeting;
??????gm.onGreeting += ChineseGreeting;
??????gm.ProcessGreeting("Edison Chou");

  5.運行顯示結果:

  Hello,Edison Chou

  你好,Edison Chou

  這里有一個問題,如果將委托聲明為private權限,那么:“這簡直就是在搞笑。因為聲明委托的目的就是為了把它暴露在類的客戶端進行方法的注冊,你把它聲明為private了,客戶端對它根本就不可見,那它還有什么用?”-(摘自張子陽的原話)

  那么如果就將委托設置為public,則客戶端可以清空監聽(即設置為null,因為它是引用類型),也可以偽造監聽(即直接調用委托),破壞了其封裝性。最后,第一個方法注冊用“=”,是賦值語法,因為要進行實例化,第二個方法注冊則用的是“+=”。但是,不管是賦值還是注冊,都是將方法綁定到委托上,除了調用時先后順序不同,再沒有任何的分別,這樣不是讓人覺得很別扭么?

  該怎么解決呢?于是Event事件閃亮登場了!!!它封裝了委托類型的變量,使得:在類的內部,不管你聲明它是public還是protected,它總是private的。在類的外部,注冊“+=”和注銷“-=”的訪問限定符與你在聲明事件時使用的訪問符相同。

  于是,我改寫GreetingManager類:

  

  public class GreetingManager
??? {
??????? public event?GreetingDelegate onGreeting;

??????? public void ProcessGreeting(string name)
??????? {
??????????? if (onGreeting != null)
??????????? {
??????????????? onGreeting(name);
??????????? }
??????? }
??? }

 這里僅僅是加了一個event標志,沒有神馬大的改變。但通過Reflector反編譯,可以看出事件其實就是一個封裝了的私有的委托而已,還包含兩個方法:add和remove;這兩個方法分別用于注冊委托類型的方法和取消注冊。實際上也就是: “+= ”對應 add_ProcessGreeting,“-=”對應remove_ProcessGreeting。而這兩個方法的訪問限制取決于聲明事件時的訪問限制符。所以,這下客戶端只能注冊、注銷事件,無法進行偽造和清空事件,保證了封裝性。

3.委托和事件的區別

  委托和事件沒有可比性,因為委托是類型,事件是對象。而委托的對象(用委托方式實現的事件)與標準event方式實現的事件的區別是:事件的內部是用委托實現的。

轉載于:https://www.cnblogs.com/edisonchou/archive/2012/03/20/2407675.html

總結

以上是生活随笔為你收集整理的C#委托与事件学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。