<ul id="qxxfc"><fieldset id="qxxfc"><tr id="qxxfc"></tr></fieldset></ul>


      一、前言


      剛開始工作的時候,覺得委托和事件有些神秘,而當你理解他們之后,也覺得好像沒有想象中的那么難。在項目中運用委托和事件,你會發(fā)現(xiàn)他非常棒,這篇博文算是自己對委托和事件的一次梳理和總結(jié)。

      二、委托

      C#中的委托,相當于C++中的指針函數(shù),但委托是面向?qū)ο蟮模前踩?,是一個特殊的類,當然他也是引用類型,委托傳遞的是對方法的引用。

      2.1、delegate

      聲明委托就必須使用關鍵字“delegate”,委托是先聲明,后實例化。至少0個參數(shù),至多32個參數(shù)

      格式如下所示:
      private delegate string GetAsString();
      委托是一個類,所以他的實例化跟類的實例化一樣,只是他總是接受一個將委托方法作為參數(shù)的構(gòu)造函數(shù)。調(diào)用委托方法就有兩種方式,如下所示:
      int i = 10; var method = new GetAsString(i.ToString); //調(diào)用方法一
      Console.WriteLine($"method方法{method()}"); //調(diào)用方法二 Console.WriteLine($"
      method.Invoke方法{method.Invoke()}");
      運行結(jié)果:


      <https://img2018.cnblogs.com/blog/1764554/201909/1764554-20190914215153740-2130519783.png>

      2.2、Action

      Action是無返回值的泛型委托,可以接受0個至16個傳入?yún)?shù)

      Action 表示無參,無返回值的委托

      Action<int,string> 表示有傳入?yún)?shù)int,string無返回值的委托

      前面我們【Log4Net 日志記錄的實現(xiàn) <https://www.cnblogs.com/snailblog/p/11484436.html>
      】中,就使用了Action。如:
      public static void Debug(string message, Action RegistedProperties) {
      RegistedProperties(); log.Debug(message); }
      調(diào)用方式為:
      PFTLog.Debug("測試擴展字段", () => { LogicalThreadContext.Properties["LogType"] = "
      擴展字段內(nèi)容"; });
      在運行中,直接運行Action中的內(nèi)容即可。

      2.3、Func

      Func是有返回值的泛型委托,可以接受0個至16個傳入?yún)?shù)

      Func<int> 表示無參,返回值為int的委托

      Func<object,string,int> 表示傳入?yún)?shù)為object, string 返回值為int的委托


      public static decimal GetTotal(Func<int, int, decimal> func, int a, int b) {
      return func(a, b); }
      調(diào)用方式
      var total = GetTotal((a, b) => { return (decimal)a + b; }, 1, 2);
      Console.WriteLine($"結(jié)果為{total}");
      運行結(jié)果


      <https://img2018.cnblogs.com/blog/1764554/201909/1764554-20190914215154463-548373136.png>

      2.4、predicate

      predicate 是返回bool型的泛型委托,只能接受一個傳入?yún)?shù)

      predicate<int> 表示傳入?yún)?shù)為int 返回bool的委托

      定義一個方法:
      public static bool FindPoints(int a) { return a >= 60; }
      定義Predicate委托
      Predicate<int> predicate = FindPoints;
      調(diào)用
      var points = new int[] { 10, 50, 60, 80, 100 }; var result =
      Array.FindAll(points, predicate); Console.WriteLine($"結(jié)果為{string.Join(";",
      result)}");
      運行結(jié)果


      <https://img2018.cnblogs.com/blog/1764554/201909/1764554-20190914215155036-2113546305.png>

      2.5、多播委托

      前面的只包含了一個方法的調(diào)用,委托可以包含多個方法,這種委托就叫做多播委托。多播委托利用“+=”和“-+”兩種運算符進行添加和刪除委托。

      先定義兩個方法
      public static void MultiplyByTwo(double v) { double result = v * 2;
      Console.WriteLine($"傳值:{v};MultiplyByTwo結(jié)果為{result}"); } public static void
      Square(double v) { double result = v * v; Console.WriteLine($"
      傳值:{v};Square結(jié)果為{result}"); }
      然后調(diào)用
      Action<double> operations = MultiplyByTwo; operations(1); operations +=
      Square; operations(2);
      運行結(jié)果:


      <https://img2018.cnblogs.com/blog/1764554/201909/1764554-20190914215155696-1425683022.png>

      三、事件

      事件是基于委托,為委托提供一種發(fā)布/訂閱機制,聲明事件需要使用event關鍵字。


      發(fā)布者(Publisher):一個事件的發(fā)行者,也稱作是發(fā)送者(sender),其實就是個對象,這個對象會自行維護本身的狀態(tài)信息,當本身狀態(tài)信息變動時,便觸發(fā)一個事件,并通知說有的事件訂閱者;

      訂閱者(Subscriber):對事件感興趣的對象,也稱為Receiver,可以注冊感興趣的事件,在事件發(fā)行者觸發(fā)一個事件后,會自動執(zhí)行這段代碼

      是不是看到sender,就有種很熟悉的感覺?。?!先不忙著急,我們先看下事件的聲明和使用


      有這樣一個應用場景,如果系統(tǒng)有異常,需要及時的通知管理員。那么需要在我們的日志記錄里面添加通知管理員的功能,但是問題來了,該怎么通知管理員呢?至少現(xiàn)在無法知道。所以我們就需要在使用到事件。

      添加代碼如下,如果不知道日志功能的可以參考【Log4Net 日志記錄的實現(xiàn)
      <https://www.cnblogs.com/snailblog/p/11484436.html>】
      //聲明一個通知的委托 public delegate void NoticeEventHander(string message);
      //在委托的機制下我們建立以個通知事件 public static event NoticeEventHander OnNotice;
      調(diào)用方式
      public static void Debug(string message, Action RegistedProperties) {
      RegistedProperties(); log.Debug(message);//執(zhí)行通知 OnNotice?.Invoke($"
      系統(tǒng)異常,請及時處理,異常信息:{message}"); }
      在引用場景的代碼,先定義一個通知管理員的方法(這里我們直接Console.WriteLine出來)
      public static void Notice(string message) { Console.WriteLine($"通知內(nèi)容為{message}
      "); }
      先注冊,然后觸發(fā)異常消息
      //注冊方式一 PFTLog.OnNotice += Notice; //注冊方式二 //PFTLog.OnNotice += new
      PFTLog.NoticeEventHander(Notice); PFTLog.Debug("測試擴展字段", () => {
      LogicalThreadContext.Properties["LogType"] = "擴展字段內(nèi)容"; });
      運行結(jié)果


      <https://img2018.cnblogs.com/blog/1764554/201909/1764554-20190914215156334-1200140224.png>

      這里面我只需要定義好發(fā)布者,你可以以任何方式訂閱,是不是很非常簡單。

      弄明白了上面的事件,我們在來說說.Net經(jīng)常出現(xiàn)的object sender和EventArgs e

      .Net Framework的編碼規(guī)范:

      一、委托類型的名稱都應該以EventHandler結(jié)束

      二、委托的原型定義:有一個void返回值,并接受兩個輸入?yún)?shù):一個Object 類型,一個 EventArgs類型(或繼承自EventArgs)

      三、事件的命名為 委托去掉 EventHandler之后剩余的部分

      四、繼承自EventArgs的類型應該以EventArgs結(jié)尾

      現(xiàn)在我們以一個新書發(fā)布的自定義事件為例

      創(chuàng)建對應的類文件:
      <https://img2018.cnblogs.com/blog/1764554/201909/1764554-20190914215156936-1856222097.png>

      事件者發(fā)布代碼:
      public class BookInfoEventArgs : EventArgs { public BookInfoEventArgs(string
      bookName) { BookName = bookName; }public string BookName { get; set; } } public
      class BookDealer { //泛型委托,定義了兩個參數(shù),一個是object sender,第二個是泛型 TEventArgs 的e
      //簡化了如下的定義 //public delegate void NewBookInfoEventHandler(object sender,
      BookInfoEventArgs e); //public event NewBookInfoEventHandler NewBookInfo; public
      event EventHandler<BookInfoEventArgs> NewBookInfo; public void NewBook(string
      bookName) { RaiseNewBookInfo(bookName); }public void RaiseNewBookInfo(string
      bookName) { NewBookInfo?.Invoke(this, new BookInfoEventArgs(bookName)); } }
      事件訂閱者
      public class Consumer { public Consumer(string name) { Name = name; } public
      string Name { get; set; } public void NewBookHere(object sender,
      BookInfoEventArgs e) { Console.WriteLine($"用戶:{Name},收到書名為:{ e.BookName}"); } }
      事件訂閱和取消訂閱
      var dealer = new BookDealer(); var consumer1 = new Consumer("用戶A");
      dealer.NewBookInfo += consumer1.NewBookHere; dealer.NewBook("book112"); var
      consumer2 =new Consumer("用戶B"); dealer.NewBookInfo += consumer2.NewBookHere;
      dealer.NewBook("book_abc"); dealer.NewBookInfo -= consumer1.NewBookHere;
      dealer.NewBook("book_all");
      運行結(jié)果


      <https://img2018.cnblogs.com/blog/1764554/201909/1764554-20190914215157581-221088652.png>

      經(jīng)過這個例子,我們可以知道Object sender參數(shù)代表的是事件發(fā)布者本身,而EventArgs e
      也就是監(jiān)視對象了。深入理解之后,是不是覺得也沒有想象中的那么難了。

      四、總結(jié)

      這里我們講了委托和事件,在.Net開發(fā)中使用委托和事件,可以減少依賴性和層的耦合,開發(fā)出具有更高的重用性的組件。

      友情鏈接
      ioDraw流程圖
      API參考文檔
      OK工具箱
      云服務器優(yōu)惠
      阿里云優(yōu)惠券
      騰訊云優(yōu)惠券
      京東云優(yōu)惠券
      站點信息
      問題反饋
      郵箱:[email protected]
      QQ群:637538335
      關注微信

        <ul id="qxxfc"><fieldset id="qxxfc"><tr id="qxxfc"></tr></fieldset></ul>
          中国美女一级特黄大片女对白 | 少妇wbb搡bbbb揉bbbb | 刑讯室a级妇刑酷刑视频 | 欧美91在线国内日韩 | A级大黄片 | 亚洲第一成网站 | 国产视频综合在线 | 一起操网 | www.色色色色.com | 91青娱乐在线视频 |