亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C# > 正文

C#中的委托數據類型簡介

2020-01-24 01:14:22
字體:
來源:轉載
供稿:網友

什么是委托?

委托是一個類型安全的對象,它指向程序中另一個以后會被調用的方法(或多個方法)。通俗的說,委托是一個可以引用方法的對象,當創建一個委托,也就創建一個引用方法的對象,進而就可以調用那個方法,即委托可以調用它所指的方法。

來看下面的例子,類deleMthod定義了3個方法,add、minus和multi,他們都具有相同的輸入參數列表(int x,int y)和輸出參數類型int,那么我們就說這三個方法具有相同的方法簽名。開發者可以抽象地用 int 某名稱(int x,int y) 的一種類型對方法進行封裝,在c#中這種抽象的數據類型叫委托,針對上述的幾個方法我們可以定義委托 : public delegate int Handler(int x ,int y),public 是一個訪問修飾符,delegate關鍵字表示這是一個委托,int Hander(int x,int y)表示這個委托的名稱。

class deleMethod{public int add(int x, int y){return x + y;}public int minus(int x, int y){return x - y;}public int multi(int x, int y){return x * y;}}

怎么使用委托

使用委托大體有四個步驟:

•定義一個委托,上節已經提及。

•定義委托方法,上節deleMethod類中add、minus、multi都是委托方法,定義的目的就是為了使用它,講專業點就是為了方法的調用

•委托變量及賦值,和類型一樣,在使用前需要對變量賦值。

•委托變量的使用。

怎樣定義委托變量,還是接著上面的例子。我們已經定義了一個委托類型 public delegate int Handler(int x,int y),和c#語法規范一樣定義一個變量并賦值語法是:“類型名 變量名 = new 類型名(方法);”,如上例

“Handler deleCall = new Handler(方法名);“,在.net2.0后對于委托的實例化可以簡化為” Handler deleCall = 方法名;“。

委托變量的使用,也就是對委托方法的調用。其語法是”int result1 = deleCall(10,20);“或者使用委托調用方法 Invoke,“int result2 = deleCall.Invoke(10,20);”。

具體如何使用可以看看下面的示例:

class Program{public delegate int Handler(int x, int y); //---定義委托的類型,可以將委托看成一種特殊的數據類型static void Main(string[] args){ deleMethod dm = new deleMethod(); //---實例化包含委托方法的類型Handler deleCall = new Handler(dm.add); //---定義委托變量delCall,并出示化賦值int result1 = deleCall(10, 20); //---實例方法的調用invokeConsole.WriteLine("the add resutl is:{0}", result1);deleCall = dm.minus;int result2 = deleCall.Invoke(12, 6);Console.WriteLine("the minus result is:{0}", result2);Console.ReadLine();}} 

如上例所示,定義一個簡單的加、減功能如此的復雜,攪來攪去讓人頭,真是無語,難怪很多朋友談委托色變暈。在實際使用的過程中,c#還是有很多方式幫我們簡化代碼。

簡化委托

預定義的泛型委托

c#系統最常見的預定義的委托類型有三種,Func<>委托、Action<>委托、Predicate<>委托,Func<>委托是一個有返回值的委托,輸入參數可以多達16個;而Action<>委托是一個沒有返回值的委托,它的輸入參數也可以多達16個;而Predicate<>是一個具有bool返回類型的委托,它只運行一個輸入參數。對于有上例的委托類型,我們可以使用預定義的委托類型Fun<int,int,int>來代替,省去我們自己定義一個什么鬼東西 public delegate int Handler(int x,int y)類型,其代碼其實可以簡化為如下例所示:

namespace DelegateDemo1{class Program{static void Main(string[] args){deleMethod dm = new deleMethod();Func<int, int, int> fun = dm.add; //---使用預定義的委托類型Func<>int result4 = fun(8, 10);Func<int, int, int> fun1 = dm.minus;int result5 = fun1(12, 8);Console.WriteLine("預定義的委托輸出{0},{1}", result4, result5);Console.ReadLine();}}class deleMethod{public int add(int x, int y){return x + y;}public int minus(int x, int y){return x - y;}public int multi(int x, int y){return x * y;}}}

我把委托的方法定義和委托的調用放在一起看,是不是比原先自己定義的一個委托類型簡單方便一些?但是這樣使用委托還是不怎么清爽,估計在實際應用中很少人會怎么寫代碼,太不方便了。

匿名委托

當委托實例的調用和委托方法的定義分開處理,碼農們在讀程序代碼的時候需要來回的去找委托方法去匹配委托變量,看看參數列表和返回值是否正確,這樣的程序代碼的可讀性很差。其實c#還是有方法讓我們簡化代碼:那就是匿名委托,將方法體直接在委托的實例化時給出,之所以叫匿名委托就是再定義委托的時候省略掉委托的名稱,它的定義語法是delegate(參數1,參數2) 后面直接就給出方法體,用大括號將方法體括起。剛看起來比較怪異,接觸多了也就習慣了,莫有辦法只能去適應c#的語法規范。話說多了是水,還不如看代碼來得直接。

namespace DelegateDemo1{class Program{static void Main(string[] args){Func<int, int, int> fun = delegate(int x, int y) { return x + y; };Func<int, int, int> fun1 = delegate(int x, int y) { return x - y; };int result4 = fun(8, 10);int result5 = fun1(12, 8);Console.WriteLine("預定義的委托輸出{0},{1}", result4, result5);Console.ReadLine();}}} 

看看是不是在原來的基礎上大幅度減少了代碼量,腫么辦,是否代碼量已經減少到極致了?

lambda表達式

其實對于委托的定義還可以進一步簡化,那就是使用lambda表達式,lambda表達式的定義是(參數列表)=>{方法體},=>讀作goes to。lambda表達式對參數列表和方法表達式的精簡達到極致,對于上面的例子,用λ表達式可以省略掉匿名委托的關鍵字和參數類型,系統可以進行類型推斷,不影響運行,其簡化的代碼如下。對.net 1.0,2.0最傳統的委托定義和使用,是一個巨大的簡化,它剔除了所有多余的語句達到極致。

namespace DelegateDemo1{class Program{static void Main(string[] args){Func<int, int, int> fun = (x, y) => x + y;Func<int, int, int> fun1 = (x, y) => x - y; int result4 = fun(8, 10);int result5 = fun1(12, 8);Console.WriteLine("預定義的委托輸出{0},{1}", result4, result5);Console.ReadLine();}}} 

委托鏈

前面講過,委托在本質上仍然是一個類,我們用delegate關鍵字聲明的所有委托都繼承自System.MulticastDelegate。后者又是繼承自System.Delegate類,System.Delegate類則繼承自System.Object。一個委托可以綁定若干相同簽名的方法形成一個委托鏈,委托鏈是一個委托實例的集合,它允許我們調用這個集合中的委托實例所代表的所有方法(對于有返回值的方法,委托鏈的返回值為鏈表中最后一個方法的返回值),在下面的例子我們定義的委托方法都沒有返回值。我們可以用 GetInvocationList()方法獲取委托鏈。

class Program{static void Main(string[] args){//Action 表示沒有返回值的一類方法Action<int, int> actionA = (x, y) =>{Console.WriteLine("x是{0},y是{1},他們的平方和是{2}", x, y, x * x + y * y);};actionA += (x, y) =>{Console.WriteLine("x是{0},y是{1},他們的平方差是{2}", x, y, x * x - y * y);};actionA(10, 5); foreach (var item in actionA.GetInvocationList())Console.WriteLine(item.Method);Console.ReadLine();}} 

什么是事件

經常看到一種定義是:事件是一種特殊的委托,是對委托的封裝。其實這種定義是很不嚴謹的。委托是一種數據類型,但是事件只是委托的實例,不能算是一種數據類型,所以說事件是一種特殊的委托是不準確的。如果這樣定義:事件是一種特殊的委托實例,是對委托的封裝。那么在C#中事件是如何定義并被使用的呢?其實事件從定義到使用要經過四個階段。

•定義事件依賴的委托,并定義事件以及引發事件的方法,該步驟可以定義在事件發布器類中

•定義事件所依賴的事件方法,該步驟可以定義在事件訂閱者類中

•如果有事件參數,該步驟可以定義在事件參數類中

•注冊事件并引發事件,該步驟一般寫在主程序中

一般來講在事件定義過程中,各個方法的命名沒有統一的標準,但我們可以參考微軟在c#中的命名規范進行命名

建議事件委托命名為:事件+EventHandler。如果有額外的參數傳遞需定義自己的參數類型,參數類型的命名規范 :事件+EventHandler。比如,可以定義一個事件委托 public delegate void calcEventHandler(object sender,calcEventArgs e); 。

定義一個事件變量如:public event calcEventHandler calc;

定義一個引發事件的方法如:public void onCalc(object sender,calcEventArgs e){}

建議方法名為 on+事件,就如同我們在開發web程序時,綁定的事件名有onClick,onLoad等一樣。

參考看下面的例子,了解定義一個事件的一般過程,如果不需要傳遞事件的參數可以省去事件參數類的定義,使用系統預定義的EventArgs就可以了。

/// <summary>/// 主程序類/// </summary>class Program{static void Main(string[] args){eventPublish myEvent = new eventPublish();eventSubscription myMethod = new eventSubscription();//綁定方法 add 和 subtract,又稱為對事件方法的注冊 -=稱為對事件方法的注銷myEvent.calc += myMethod.add;myEvent.calc += myMethod.substract;while (true){try{Console.WriteLine("請輸入第一個整數數");int numA = Convert.ToInt16(Console.ReadLine());Console.WriteLine("請輸入第二個整數");int numB = Convert.ToInt16(Console.ReadLine());calcEventArgs e = new calcEventArgs(numA, numB);//在本例不需要sender參數,隨意傳遞了字符串"sender"myEvent.onCalc("sender", e); }catch (Exception ex){Console.WriteLine("出現錯誤," + ex.Message);}}}}/// <summary>/// 定義一個事件發布器類/// </summary>class eventPublish{//定義一個委托類型,委托名一般是 事件變量名+EventHandlerpublic delegate void calcEventHander(object sender,calcEventArgs e);//定義一個事件變量,其變量名為calcpublic event calcEventHander calc;//封裝事件,對外定義了引發事件的方法,定義的引發方法名一般是 on+事件變量名public void onCalc(object sender, calcEventArgs e){if (calc != null)calc(sender,e);}}/// <summary>/// 定義一個事件訂閱者類(事件方法類)/// </summary>class eventSubscription{public void add(object sender, calcEventArgs e){Console.WriteLine("兩數相加等于{0}", e.X + e.Y );}public void substract(object sender, calcEventArgs e){Console.WriteLine("兩數相減等于{0}", e.X - e.Y);}}/// <summary>/// 定義一個事件參數類/// </summary>class calcEventArgs : EventArgs{private int _x;private int _y;public calcEventArgs(int x, int y){this._x = x;this._y = y;}public int X{get { return _x; }}public int Y{get { return _y; }}}

我們將事件是對委托的封裝,如果用ILDAS反編譯可執行文件查看中間代碼就可以非常明了的看出事件運行機制


如上圖所示,事件calc,經.net運行時編譯為中間語言后產生了一個private 的calc屬性,同時也自動生成了add_calc和remove_calc方法,用于注冊和注銷訂閱者方法。因為事件是被封裝的,盡管calc屬性是private,但在所以在發布器類內部可以用 calc(sender,e)這樣的方法直接調用;但在主程序中如果這樣使用就會出錯,只能通過onCalc方法進行間接調用。

后記

  本篇文章,一開始提出了什么是委托的疑問,通過引入幾個方法來講述委托是什么以加強對委托概念的理解。第二部分講述了使用委托的四個步驟,并通過示例闡述了這幾個步驟。第三部分講述了委托使用的簡化問題,通過使用泛型委托簡化自定義委托,通過使用匿名委托可以簡化定義委托方法。匿名委托是在定義委托的時候直接給出方法體,通過使用lambda表達式的類型推斷可進一步簡化委托的使用。第四部分講述了委托鏈,通過綁定方法初始化委托,并通過+=綁定更多的委托方法。第五部分講述了事件的定義和使用的四個步驟。當然委托的使用場景還有很多,比如通過BeginInvoke和EndInvoke進行異步調用,因不是本篇文章的重點,所以文章中沒有提及。

以上內容是小編給大家介紹的C#中的委托數據類型簡介,希望對大家有所幫助!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩hd视频在线观看| 色综合久综合久久综合久鬼88| 国产视频欧美视频| 久久亚洲精品视频| 成人久久久久久| 成人激情黄色网| 国产主播喷水一区二区| 亚洲国产成人在线视频| 亚洲电影免费观看高清完整版在线| 亚洲欧洲在线观看| 精品成人在线视频| 亚洲精品ady| 国产精品偷伦一区二区| 亚洲精品美女久久久久| 性色av香蕉一区二区| 欧美最近摘花xxxx摘花| 久久综合88中文色鬼| 91久久国产婷婷一区二区| 欧美激情综合亚洲一二区| 精品久久久久国产| 欧美成人免费全部观看天天性色| 日韩日本欧美亚洲| 亚洲自拍另类欧美丝袜| 国产精品久久婷婷六月丁香| 亚洲国产精品小视频| 欧美韩日一区二区| 5252色成人免费视频| 在线国产精品播放| 性欧美xxxx视频在线观看| 久久国产精品久久久久| 欧美激情一区二区久久久| 91精品国产91久久| 日韩精品在线影院| 日韩精品免费电影| 久久久久久91香蕉国产| 中日韩午夜理伦电影免费| 九九热精品视频| 亚洲在线视频观看| 日韩高清中文字幕| 精品动漫一区二区三区| 欧美黑人巨大精品一区二区| 国产精品mp4| 国产精品久久久久久久久久久久| 精品视频偷偷看在线观看| 日韩免费观看视频| 96pao国产成视频永久免费| 欧美丰满少妇xxxxx做受| 国产成人综合av| 欧美性少妇18aaaa视频| 一区二区国产精品视频| 亚洲免费人成在线视频观看| 欧美性在线观看| 日韩视频一区在线| 日韩成人在线网站| 亚洲欧美日韩一区二区三区在线| 综合国产在线观看| 国产亚洲美女精品久久久| 日韩欧美精品免费在线| 久久国内精品一国内精品| 亚洲性无码av在线| 亚洲精品国产欧美| 亚洲福利精品在线| 最近2019年日本中文免费字幕| 欧美日韩国产91| 成人免费看黄网站| 日韩精品免费在线观看| 中文国产亚洲喷潮| 色黄久久久久久| 丁香五六月婷婷久久激情| 成人午夜一级二级三级| 69**夜色精品国产69乱| 亚洲欧洲日产国码av系列天堂| 欧美日韩国产精品专区| 成人有码在线播放| 国产在线久久久| 亚洲高清一区二| 国产精品久久国产精品99gif| 亚洲成年人在线| 亚洲色图五月天| 欧美在线日韩在线| 久久精品视频在线观看| 国产午夜精品视频| 美女福利精品视频| 91免费福利视频| 精品国产区一区二区三区在线观看| 亚洲最大的免费| 亚洲男人av在线| 久久久久久久影院| 在线中文字幕日韩| 欧美高清videos高潮hd| 欧美极品少妇xxxxⅹ免费视频| 有码中文亚洲精品| 欧美一区二区大胆人体摄影专业网站| 欧美色视频日本高清在线观看| 欧美国产高跟鞋裸体秀xxxhd| 亚洲人在线观看| 精品久久久久久久久久ntr影视| 久久久精品免费| 日韩欧美在线第一页| 欧美影院在线播放| 国外日韩电影在线观看| 欧美国产视频一区二区| 国产精品777| 国产性猛交xxxx免费看久久| 国产精品视频一区二区三区四| 国产欧美va欧美va香蕉在线| 国产精品91久久久久久| 国产精品成人一区| 亚洲精品v天堂中文字幕| 国产综合色香蕉精品| 午夜精品视频网站| 日韩最新免费不卡| 欧美日韩免费在线观看| 海角国产乱辈乱精品视频| 91精品国产综合久久男男| 97碰碰碰免费色视频| 亚洲国产精品高清久久久| 91亚洲国产成人久久精品网站| 欧美日韩国产激情| 亚洲精品综合久久中文字幕| 亚洲国产精品系列| 国产精品久久久久久久久久久久久| 国产免费观看久久黄| 亚洲国产精品美女| 欧美在线亚洲一区| 8x海外华人永久免费日韩内陆视频| 亚洲欧洲日本专区| 久久综合伊人77777蜜臀| 国产精品美女www爽爽爽视频| 亚洲影影院av| 亚洲欧美日韩高清| 国产精品第一页在线| 欧美大片在线看免费观看| 欧美专区第一页| 国产成人a亚洲精品| 成人性生交大片免费观看嘿嘿视频| 热久久这里只有| 欧美性videos高清精品| 97超碰国产精品女人人人爽| 国产97在线|亚洲| 不卡伊人av在线播放| www.欧美精品| 亚洲自拍偷拍色图| 亚洲国产精品大全| 久久精品国产一区二区电影| www.精品av.com| 精品夜色国产国偷在线| 日韩电影第一页| 久久久亚洲影院你懂的| 亚洲国产精品va在看黑人| 欧美高清在线播放| 欧美激情亚洲综合一区| 亚洲成人黄色网址| 日韩在线观看网址| 亚洲а∨天堂久久精品喷水| 欧美国产日产韩国视频| 欧美激情精品久久久久久大尺度| 欧美日韩激情视频| 日韩一区视频在线| 亚洲精品美女在线观看| 91po在线观看91精品国产性色| 57pao成人永久免费视频| 欧美日韩精品中文字幕| 久久久久国产精品一区|