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

首頁 > 編程 > C# > 正文

C#沉淀之委托的深入講解

2019-10-29 19:58:44
字體:
來源:轉載
供稿:網友

什么是委托

要傳遞方法,就必須把方法的細節封裝在一鐘新類型的對象中,即委托。委托是一種特殊類型的對象,其特殊之處在于,我們以前定義的所有對象都包含數據,而委托只包含一個或多個方法的地址。

.NET版本中,委托指向方法的地址。在C++中,函數指針是一個指向內存位置的指針,但它不是類型安全的。開發者無法判斷這個指針實際指向什么,像參數和返回值等項就更不知道了。

.NET委托是類型安全的類,它定義了返回類型和參數的類型。委托類不僅包含對方法的引用,也可以包含對多個方法的引用。

可以認為委托是持有一個或多個方法的對象。委托可以被執行,執行委托時委托會執行它所“持有”的方法

代碼示例:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace CodeForDelegate{ //使用關鍵字delegate聲明委托類型 //委托是一種類型,所以它與類屬于同一級別 //注意:這里是委托類型,而不是委托對象 delegate void MyDel(int value); class Program {  void PrintLow(int value)  {   Console.WriteLine("{0} - Low Value", value);  }  void PrintHigh(int value)  {   Console.WriteLine("{0} - High Value", value);  }  static void Main(string[] args)  {   //實例化Program類,以訪問PrintLow和PrintHigh方法   Program program = new Program();   //聲明一個MyDel類型的委托   MyDel del;   //創建隨機數   Random rand = new Random();   int randomvalue = rand.Next(99);   //使用三目運算符根據當前隨機數的值來創建委托對象   del = randomvalue < 50    ? new MyDel(program.PrintLow)    : new MyDel(program.PrintHigh);   //執行委托   del(randomvalue);   Console.ReadKey();  } }}

從上例可以看出,使用委托的首先得通過關鍵字delegate聲明一個委托類型,這個委托類型包括返回值、名稱、簽名;當類型聲明好以后,需要通過new來創建委托對象,創建對象時的參數是一個方法,這個方法的簽名和返回類型必須與該委托類型定義的簽名一致;調用委托時,直接通過實例化的委托對象名,并提供參數即可,然后委托會執行在其所持有的方法

委托與類

委托和類一樣,是一種用戶自定義的類型;不同的是類表示的是數據和方法的集合,而委托持有一個或多個方法,以及一系列預定義操作

委托的使用步驟

  • 聲明一個委托類型
  • 使用該委托類型聲明一個委托變量
  • 創建委托類型的對象,把它賦值給委托變量;委托對象中包括指向某個方法的引用,此方法和委托類型定義的簽名與返回類型需要一致
  • 增加更多的方法(可選)
  • 像調用方法一樣調用委托(委托中的包含的每一個方法都會被執行)

delegate的原則

delegate相當于一個包含有序方法列表的對象,這些方法都具有相同的簽名和返回類型

方法的列表稱為調用列表

委托保存的方法可以來自任何類或結構,只要它們在以下兩點匹配:

  • 委托的返回類型
  • 委托的簽名(包括ref和out修飾符)

調用列表中的方法可以是靜態方法也可以是實例方法

在調用委托的時候,會調用列表中的所有方法

聲明委托類型

如下,delegate關鍵字開關,然后是返回類型,再定義名稱與簽名

delegate void MyDel(int vallue);

返回類型與簽名指定了委托接受的方法形式

注意:委托類型是沒有方法主體的

創建委托對象

使用new運算符創建對象

MyDel del = new MyDel(object.Func); //object.Func是個實例方法Mydel _del = new MyDel(Object.Func); //Object.Func是個靜態方法

使用快捷語法創建對象

MyDel del = object.Func; //object.Func是個實例方法Mydel _del = Object.Func; //Object.Func是個靜態方法

這種語法是能夠工作是因為在方法名稱和其相應的委托類型之間存在隱式的轉換

創建委托對象后會將指定的方法加入到委托的調用列表中

由于委托是引用類型,可以通過賦值來改變包含在委托變量中的引用,如下:

MyDel del;del = new MyDel(object.FuncA); //創建第一個對象del = new MyDel(object.FuncB); //創建第二個對象

由于第二個對象也賦值給了變量del,因此del所引用的第一個對象將被垃圾回收器回收

組合委托

//創建兩個委托MyDel del_A = new MyDel(object.FuncA);Mydel del_B = new MyDel(object.FuncA);//組合委托MyDel del_C = del_A + del_B;

當將del_A與del_B通過+進行組合后,會返回一個新的委托對象,該對象將del_A與del_B中的方法調用列表組合到新的對象里,該新對象賦值給變量del_C,所以執行del_C的時候,會執行del_A與del_B中所保存的方法object.FuncA和object.FuncA

委托添加多個方法

MyDel del = object.FuncA; //創建并初始化委托對象del += object.FuncB; //增加方法del += object.FuncC; //增加方法

通過+=符號為委托對象添加更多方法,上例中,del對象不保存了三個方法,在執行del時,這三個方法會被依次調用

注意,在使用+=為委托對象添加新的方法時,實際上是創建了一個新的委托對象(原對象的副本)

移除委托方法

del -= object.FuncB; //移除方法del -= object.FuncC; //移除方法

通過-=來將委托調用列表中已保存的方法,移除動作是從調用列表的最后一個方法開始匹配,一次只會移除一條匹配的方法,如果調用列表中不存在該方法,則沒有任何效果;如果試圖調用一個空的委托則會發生異常

注意,在使用-=為委托對象移除方法時,實際上是創建一個新的委托對象(原對象的副本)

調用委托

調用委托就像調用方法一樣

示例:MyDel類型參考上面的定義

MyDel del = object.FuncA; //創建并初始化委托對象del += object.FuncB; //增加方法del += object.FuncC; //增加方法//調用委托 del(55);

參數55會在調用委托對象時依次傳遞給保存的方法

一個完整的委托示例代碼

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace CodeForDelegate{ class Program {  //定義委托類型  delegate void PrintFunction(string txt);  //測試類中定義三個方法  class Test  {   public void PrintA(string txt)   {    Console.WriteLine("printA:{0}", txt);   }   public void PrintB(string txt)   {    Console.WriteLine("printB:{0}", txt);   }   public static void PrintC(string txt)   {    Console.WriteLine("printC:{0}", txt);   }  }  static void Main(string[] args)  {   Test test = new Test();   PrintFunction pf;   //實例化并創建委托對象   pf = test.PrintA;   //為委托對象增加方法   pf += test.PrintB;   pf += Test.PrintC;   pf += test.PrintA; //添加一個重復的方法   //通過與null比較,確認委托對象中保存了方法   if (pf != null)    pf("Hello");   else    Console.WriteLine("pf是個空委托!");   Console.ReadKey();  } }}

調用帶有返回值的委托

如何委托有返回值,并且調用列表中有一個以上的方法,那么將使用最后一個方法的返回值,之前方法的返回值被忽略

示例:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace CodeForDelegate{ class Program {  //定義委托類型  delegate int DelFunction();  //測試類中定義三個方法  class Test  {   int IntValue = 0;      public int FuncA()   {    return IntValue += 1;   }   public int FuncB()   {    return IntValue += 10;   }  }  static void Main(string[] args)  {   Test test = new Test();   DelFunction df;   df = test.FuncA;   df += test.FuncB;   //最終返回值的是11   if (df != null)    Console.WriteLine("返回值:"+df());   else    Console.WriteLine("pf是個空委托!");   Console.ReadKey();  } }}

具有引用參數的委托

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace CodeForDelegate{ //定義委托類型 delegate void MyDel(ref int x); class Program {  static void Add1(ref int x) { x += 1; }  static void Add2(ref int x) { x += 2; }  static void Main(string[] args)  {   Program program = new Program();   MyDel del = Add1;   del += Add2;   //ref會將x當作引用值傳遞給委托方法   int x = 5;   del(ref x);   Console.ReadKey();  } }}

在調用Add1方法時,x = 5+1,再調用Add2方法時,不是x = 5+2而是x = 6 +2

參考:ref按引用傳遞參數

在方法的參數列表中使用 ref 關鍵字時,它指示參數按引用傳遞,而非按值傳遞。 按引用傳遞的效果是,對所調用方法中參數進行的任何更改都反映在調用方法中。 例如,如果調用方傳遞本地變量表達式或數組元素訪問表達式,所調用方法會替換 ref 參數引用的對象,然后,當該方法返回時,調用方的本地變量或數組元素將開始引用新對象

匿名方法

匿名方法是在初始化委托時內聯聲明的方法

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace CodeForDelegate{ //定義委托類型 delegate void MyDel(ref int x); class Program {  static void Add1(ref int x) { x += 1; }  static void Add2(ref int x) { x += 2; }  static void Main(string[] args)  {   Program program = new Program();      //采用匿名方法形式代替具名方法   MyDel del = delegate(ref int y) { y += 3; };   del += Add1;   del += Add2;   //ref會將x當作引用值傳遞給委托方法   int x = 5;   del(ref x);   Console.ReadKey();  } }}

在聲明委托變量時作為初始化表達式,或在為委托增加事件時使用

語法解析

以關鍵字delegate開頭;后跟小括號提供參數;再后跟{}作為語句塊

delegate (Parameters) {ImplementationCode}

  • 匿名方法不會顯示的聲明返回類型delegate (int x) { return x;}即為返回一個int類型的值
  • 參數的數量、位置、類型、修飾符必須與委托相匹配
  • 可以通過省略圓括號或使圓括號為空來簡化匿名方法的參數列表,前提是參數是不包含out參數,方法體中不使用任何參數

示例:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace CodeForDelegate{ //定義委托類型 delegate void MyDel(ref int x); class Program {  static void Add1(ref int x) { x += 1; }  static void Add2(ref int x) { x += 2; }  static void Main(string[] args)  {   Program program = new Program();      //采用匿名方法形式代替具名方法   MyDel del = delegate(ref int y) { y += 3; };   del += Add1;   del += Add2;      //匿名方法未使用任何參數,簡化形式   del += delegate{int z = 10;};   //ref會將x當作引用值傳遞給委托方法   int x = 5;   del(ref x);   Console.ReadKey();  } }}

如果定義一個帶有params形式的參數,在使用匿名方法的時候可以省略params關鍵字以簡化代碼

示例:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace CodeForDelegate{ //定義一個帶有params形式參數的委托類型 delegate void DelFunction(int x, params int[] z); class Program {  static void Main(string[] args)  {   Program program = new Program();      // 關鍵字params被忽略(省略關鍵字以簡化)   DelFunction df = delegate(int x, int[] y) { ... };   Console.ReadKey();  } }}

Lambda表達式

Lambda可以簡化匿名方法,語法形式如下:

(參數) => {語句塊} // => 讀作 gose to

參數中的類型可以省略
如果只有一個參數,圓括號可以省略
如果沒有參數,圓括號不可以省略
語句塊如果只有一行代碼,花括號可以省略

示例:

MyDel del = delegate(int y) { return y += 3; }; //匿名方法MyDel del1 = (int y) => {return y += 3;} // Lambda表達式MyDel del2 = (y) => {return y += 3;} // 省略參數類型MyDel del3 = y => y += 3; // 省略圓括號和花括號,雖然沒有return,但仍會返回y的值

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網的支持。


注:相關教程知識閱讀請移步到c#教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
91精品国产成人| 2019亚洲男人天堂| 国产一区二区成人| 日韩成人av在线| 中文字幕av日韩| 亚洲欧洲在线免费| 亚洲视频777| 国产精品美女久久| 亚洲第一区第二区| 97在线视频免费观看| 91免费视频网站| 在线精品国产欧美| 久久九九国产精品怡红院| 亚洲精品久久久久久久久久久久| 97免费视频在线| 国产精品自产拍在线观看中文| 国产亚洲精品综合一区91| 黄色一区二区在线观看| 日韩欧美极品在线观看| 91久久久久久久| 日韩欧美一区视频| 日韩高清欧美高清| 久久777国产线看观看精品| 日韩av电影中文字幕| 国产一区av在线| 亚洲色图综合久久| 亚洲视频欧美视频| 国产日韩专区在线| 久久久噜噜噜久久久| 姬川优奈aav一区二区| 亚洲国产欧美日韩精品| 欧美一区二区三区免费观看| 国产在线观看91精品一区| 97精品伊人久久久大香线蕉| 国产一区二区三区在线播放免费观看| 亚洲第一精品夜夜躁人人爽| 日韩精品在线私人| 91欧美精品午夜性色福利在线| 亚洲人成免费电影| 久久久精品在线| 另类天堂视频在线观看| 亚洲免费精彩视频| 国产精品嫩草影院久久久| 欧美一级片免费在线| 91中文字幕在线观看| 久久免费在线观看| 日韩电影在线观看中文字幕| 国产精品极品美女粉嫩高清在线| 日本午夜精品理论片a级appf发布| 日韩hd视频在线观看| 欧美最猛性xxxxx亚洲精品| 日韩欧美国产一区二区| 国产精品视频精品| 红桃av永久久久| 亚洲精品一区久久久久久| 国产精品1234| 一本色道久久综合狠狠躁篇怎么玩| 午夜欧美不卡精品aaaaa| 成人a免费视频| 久久综合伊人77777尤物| 亚洲激情中文字幕| 日韩视频欧美视频| 国产精品视频1区| 欧美天天综合色影久久精品| 91夜夜揉人人捏人人添红杏| 亚洲字幕在线观看| 久久夜色精品国产欧美乱| 26uuu国产精品视频| 欧美性色19p| 精品视频在线播放免| 久久激情五月丁香伊人| 中文欧美在线视频| 在线播放国产一区二区三区| 成人欧美一区二区三区黑人孕妇| 91av网站在线播放| 日韩电影免费在线观看中文字幕| 国产一区二区欧美日韩| 91啪国产在线| 欧美成人午夜免费视在线看片| 欧美又大粗又爽又黄大片视频| 欧美性一区二区三区| 成人国产在线激情| 成人精品一区二区三区| 成人午夜在线观看| 亚洲综合在线中文字幕| 欧美激情按摩在线| 精品国产老师黑色丝袜高跟鞋| 国产人妖伪娘一区91| 久久99久久久久久久噜噜| 亚洲人成电影网站色| 最近2019中文免费高清视频观看www99| 久久不射电影网| 欧美专区国产专区| 久久国产精品久久精品| 97视频在线观看亚洲| zzijzzij亚洲日本成熟少妇| 欧美一级大片在线观看| 国产精品视频区1| 亚洲电影中文字幕| 91精品久久久久久久久久另类| 国产精品wwwwww| 久久久久久久久网站| 日韩毛片在线观看| 91九色在线视频| 精品国产一区二区三区久久| 欧美性xxxx极品高清hd直播| 国产午夜精品理论片a级探花| 久久久久北条麻妃免费看| 国产精品大陆在线观看| 亚洲va男人天堂| 岛国av一区二区三区| 91影院在线免费观看视频| 久热精品在线视频| 国产成人精品日本亚洲专区61| 亚洲欧美在线一区二区| 一区二区日韩精品| 国产亚洲免费的视频看| 久久久噜久噜久久综合| 国产精品老女人精品视频| 精品国产乱码久久久久久天美| 亚洲国产日韩欧美在线图片| 中文字幕亚洲欧美日韩在线不卡| 国产精品看片资源| 久久国产精品电影| 国产91ⅴ在线精品免费观看| 亚洲毛片在线观看| 欧美一乱一性一交一视频| 久久久人成影片一区二区三区| 国产成人精品电影| 久久手机免费视频| 日韩中文字幕在线视频播放| 亚洲欧美日本另类| 91香蕉嫩草影院入口| 成人做爰www免费看视频网站| 久久亚洲影音av资源网| 68精品久久久久久欧美| 欧美激情亚洲一区| 亚洲精品免费一区二区三区| 伦伦影院午夜日韩欧美限制| 欧美国产日韩一区二区| 77777亚洲午夜久久多人| 欧美疯狂做受xxxx高潮| 九九热99久久久国产盗摄| 亚洲欧美成人网| 成人黄色网免费| 欧美午夜激情视频| 一区二区欧美激情| 69**夜色精品国产69乱| 亚洲老板91色精品久久| 综合网日日天干夜夜久久| 91视频免费网站| 国产精品a久久久久久| 久久精品人人爽| 懂色av影视一区二区三区| 国产精品2018| 欧美综合国产精品久久丁香| 亚洲欧美日韩精品久久奇米色影视| 97**国产露脸精品国产| 国产精品久久久久久一区二区| 亚洲国产欧美一区二区丝袜黑人| 91精品国产777在线观看| 久久久久国产精品一区| 成人一区二区电影| 亚洲乱码国产乱码精品精天堂|