那些年困擾我們的委托(C#)。本站提示廣大學習愛好者:(那些年困擾我們的委托(C#))文章只能為提供參考,不一定能成為您想要的結果。以下是那些年困擾我們的委托(C#)正文
委托這個東西不是很好了解,可是任務中又常常用到,你隨處可以看到它的身影,真讓人有一種又愛又恨的覺得,我置信許多人被它所困擾過。
一提到委托,假如你學過C言語,你一定會馬上聯想到函數指針。
什麼是委托?委托是C#中類型平安的,可以訂閱一個或多個具有相反簽名辦法的函數指針。委托可以把函數做為參數傳遞,其實踐意義便是讓他人代理你的事情。委托可以看做是函數的指針,整數可以用整數變量指向它,對象可以用對象變量指向它,
函數也可以用委托變量指向它。我們可以選擇將委托類型看做只定義了一個辦法的接口,而委托的實例可以看做是完成了那個接口的一個對象。
運用委托,必需滿足4個條件:
聲明委托的方式:delegate 前往值類型 委托類型名(參數)
委托的聲明和接口辦法的聲明根本上分歧,只是在前往類型關鍵字的後面多了一個delegate關鍵字。
有如下四種委托:
//1.無參數無前往值 public delegate void NoParaNoReturnEventHandler(); //2.有參數無前往值 public delegate void WithParaNoReturnEventHandler(string name); //3.無參數有前往值 public delegate string NoParaWithReturnEventHandler(); //4.有參數有前往值 public delegate string WithParaWithReturnEventHandler(string name);
假如代碼想要執行操作,但不知道操作細節,普通可以運用委托。例如, Thread類之所以知道要在一個新線程裡運轉什麼,獨一的緣由就是在啟動新線程時,向它提供了一個ThreadStart或ParameterizedThreadStart委托實例。
Thread th = new Thread(Test); th.Start(); public Thread(ThreadStart start); public delegate void ThreadStart();
ThreadStart是一個無參無前往值的委托。
static void Test() { Console.WriteLine("線程辦法"); }
這個Test辦法的函數簽名必需和委托ThreadStart的函數簽名分歧。
委托的調用必需先實例化委托,然後再調用。
函數的簽名和委托的簽名必需分歧。NoParaNoReturnEventHandler _NoParaNoReturnEventHandler = ConsoleInfo;,編譯器幫我們停止了new,但是不能寫成NoParaNoReturnEventHandler _NoParaNoReturnEventHandler = ConsoleInfo();
由於這樣就成為了函數調用。
#region 無前往值委托調用 public static void Show() { //實例化委托 NoParaNoReturnEventHandler _NoParaNoReturnEventHandler = new NoParaNoReturnEventHandler(ConsoleInfo); //NoParaNoReturnEventHandler _NoParaNoReturnEventHandler = ConsoleInfo; //簡寫 //委托調用 經過Invoke()調用,或許可以直接省略 _NoParaNoReturnEventHandler.Invoke(); //_NoParaNoReturnEventHandler(); } private static void ConsoleInfo() { Console.WriteLine("無參數無前往值的函數調用"); } #endregion為什麼要運用委托
我們完全可以直接調用辦法,為什麼還需求經過一個委托來調用呢?委托有什麼意義?
對修正封閉,對擴展開放。邏輯別離。
你可以把委托了解為函數的父類,或許是一個辦法的占位符。
我們來看下代碼,假定有2個辦法,一個說英語,一個說漢語,而這2個辦法的函數簽名是一樣的。
public static void SayChinese(string name) { Console.WriteLine("你好," + name); } public static void SayEnglish(string name) { Console.WriteLine("hello," + name); }
那麼我們在內部調用的時分,
MyDelegate.SayChinese("張三"); MyDelegate.SayEnglish("zhangsan");
假如要調用這兩個不同的辦法,是不是要寫不同的調用代碼
我們能不能只一個辦法調用呢?修正代碼如下:
public static void Say(string name,WithParaNoReturnEventHandler handler) { handler(name); } public static void SayChinese(string name) { Console.WriteLine("你好," + name); } public static void SayEnglish(string name) { Console.WriteLine("hello," + name); }
這樣,只經過一個辦法Say來停止調用。
如何調用呢?如下三種調用方式:
WithParaNoReturnEventHandler _WithParaNoReturnEventHandler = new WithParaNoReturnEventHandler(MyDelegate.SayChinese); MyDelegate.Say("張三",_WithParaNoReturnEventHandler); MyDelegate.Say("張三", delegate(string name) { Console.WriteLine("你好," + name); }); //匿名辦法 MyDelegate.Say("張三", (name) => { Console.WriteLine("你好," + name); }); //lambda表達式
以上代碼運用了幾種調用方式,這些調用方式都是隨著C#的晉級而不時優化的。第一種是C#1.0中就存在的傳統調用方式,第二種是C#2.0中的匿名辦法調用方式,所謂匿名辦法,就是沒有名字的辦法,當辦法只調用一次時運用匿名辦法最適宜不過了。C#3中的lambda表達式。其實泛型委托異樣是被支持的,而.NET 3.5則更進一步,引入了一組名為Func的泛型委托類型,它能獲取多個指定類型的參數,並前往另一個指定類型的值。
也就是說詳細調用什麼樣的辦法,完全由調用方決議了,就有了更大的靈敏性和擴展性。為什麼這麼說,假如我有些時分要先說英語再說漢語,有些事時分要先說漢語再說英語,假如沒有委托,我們會怎樣樣完成?請看如下代碼:
public static void SayEnglishAndChinese(string name) { SayEnglish(name); SayChinese(name); } public static void SayChineseAndEnglish(string name) { SayChinese(name); SayEnglish(name); }
假如又忽然要添加一種俄語呢?被調用方的代碼又要修正,如此循環下去,是不是要抓狂了?隨著不時添加新語種,代碼會變得越來越復雜,越來越難以維護。當然,你可以經過設計形式,在不運用委托的狀況上去重構代碼,但是完成起來是十分費事的,要寫很多更多的代碼...
委托可以傳遞辦法,而這些辦法可以代表一系列的操作,這些操作都由調用方來決議,就很好擴展了,而且非常靈敏。我們不會對已有的辦法停止修正,而是只以添加辦法的方式去停止擴展。
能夠有人又會說,我直接在調用方那裡來一個一個調用我要執行哪些辦法一樣可以完成這樣的效果啊?
可你有沒有想過,你要調用的是一系列辦法,你基本無法復用這一系列的辦法。運用委托就不一樣了,它好比一個辦法集合的容器,你可以往外面增減辦法,可以復用的。而且運用委托,你可以延時辦法列表的調用,還可以隨時對辦法列表停止增減。委托對辦法停止了再一次的封裝。
總結:也就是當你只能確定辦法的函數簽名,無法確定辦法的詳細執行時,為了可以更好的擴展,以相似於注入辦法的方式來完成新增的功用,就能表現出委托的價值。
委托和直接調用函數的區別:用委托就可以指向恣意的函數,哪怕是之前沒定義的都可以,而不必受限於哪幾種。
組合的委托必需是同一個類型,其相當於創立了一個依照組合的順序順次調用的新委托對象。委托的組合普通是給事情用的,用普通委托的時分很少用。
經過+來完成將辦法添加到委托實例中,-來從委托實例中停止辦法的移除。
+和-地道是為了簡化代碼而生的,實踐上其調用的辨別是Delegate.Combine辦法和Delegate.Remove。
假如委托中存在多個帶前往值的辦法,那麼調用委托的前往值是最後一個辦法的前往值。
public static void MultipleShow() { //多播委托 NoParaWithReturnEventHandler _NoParaWithReturnEventHandler = new NoParaWithReturnEventHandler(GetDateTime); _NoParaWithReturnEventHandler += GetDateTime; Console.WriteLine(_NoParaWithReturnEventHandler()); } public static string GetDateTime() { return string.Format("明天是{0}號。", DateTime.Now.Day.ToString()); }
委托總結:
罕見運用場景:窗體傳值、線程啟動時綁定辦法等等。
生活中的例子:如今不是大家都在搶火車票嗎,運用雲搶票就相當於運用委托,你可以直接自己買票,也可以托管於雲搶票,自己搶票的話,在快要開槍的時分,你必需時辰刷新,下單輸驗證碼等等,運用雲搶票的話,你只需放票前,提早輸出搶票信息,就再也不需求你管了,自動出票,你基本不需求知道雲搶票那邊是怎樣幫你完成搶票的。相反時間和車次可以做成一個委托實例,有很多人都經過這個委托實例來停止搶票操作。
源碼下載:http://pan.baidu.com/s/1mic3QjQ