<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      Fork me on GitHub

      .NET 中的委托

      1.1.1 定義

        委托是一種引用方法的類型。一旦為委托分配了方法,委托將與該方法具有完全相同的行為。委托方法的使用可以像其他任何方法一樣,具有參數和返回值,如下面的示例所示:

        //Code in C#

        public delegate int PerformCalculation(int x, int y);

        與委托的簽名(由返回類型和參數組成)匹配的任何方法都可以分配給該委托。

        簡單理解Delegate委托(或代理)是一種數據類型:它的變量可以引用到某一個符合要求的方法上,通過委托可以間接地調用該方法。

        其實.NET的委托類似于C語言的函數指針,區別在于.NET委托是類型安全的,這說明,C中的函數指針只不過是一個指向存儲單元的指針,我們無法說出這個指針實際指向什么。

      1.1.2 委托使用

      • 使用委托的四部曲:
      • 定義一種委托類型
      • 委托執行時要調用方法
      • 定義一個委托實例
      • 委托實例的調用

        我們先定義一種委托類型如下:

      //自定義一種委托類型

      public delegate void StringProcessor(string input);

      然后我們再定義5中候選的委托方法如下:

      void PrintString(string x)

      void PrintInteger(int x)

      void PrintTwoStrings(string x, string y)

      int GetStringLength(string x)

      void PrintObject(object x)

        大家猜猜看哪個和上面提供的委托類型簽名匹配(簽名匹配:參數類型,參數個數和返回類型匹配)。激動時刻到了馬上公布答案,和委托類型匹配的方法是PrintString和PrintObject,如果有不明白的請細細考慮一下委托匹配的條件—簽名匹配。

                                           

      圖1委托成功輸出

       

        現在對委托有了一定的認識,接下來我們將介紹委托最經常使用的地方—事件。

        我們將從發送器和接受器的角度討論事件,例如在UI編程中,鼠標單擊或鍵盤按鍵,發送器就是.NET的CLR,注意事件發送器并不知道接收器是誰,這符合面向對象的原則,而且某個事件接收器有個方法處理該事件,這個時候就要委托,如前面所講事件發送器對事件接收器一無所知,通過委托作為一個中介,接收器把事件處理方法注冊到事件中,這樣就實現了由發送器->委托->接收器的過程了。

        我們可以這樣認為:委托是一個類,它定義了方法的類型,使得可以將方法當作另一個方法的參數來進行傳遞,這種將方法動態地賦給參數的做法,可以避免在程序中大量使用If-Else(Switch)語句,同時使得程序具有更好的可擴展性。

        

      1.1.3 自定義委托

        前面話有點難以理解,接下來我們通過具體的例子分析一下何謂委托,該如何實現委托。現在不是很喜歡搞多國語言化的嗎?看看如何讓我們的程序會說多種語言吧!

      /// <summary>
      /// the English speaker.
      /// </summary>
      /// <param name="name">The name.</param>
      public void EnglishSpeaker(string name)
      {
      Console.WriteLine(
      string.Format("Hello my name is {0} and I am English speaker.\n", name));
      }

      /// <summary>
      /// the Chineses speaker.
      /// </summary>
      public void ChineseSpeaker(string name)
      {
      Console.WriteLine(
      string.Format("您好我的名字叫{0},我是講普通話的。\n", name));
      }

        好啦現在我們有兩個方法分別是說普通話和英語,現在我們的程序會說普通話和英語啦。現在我們考慮究竟什么時候講普通話什么時候講英語,那不簡單我們加個判斷就OK啦,是的我們可以通過switch或者if else就可以實現啦。

      /// <summary>
      /// 根據上下文調用不同的方法
      /// </summary>
      /// <param name="name">string</param>
      /// <param name="lang">enum</param>
      private static void Say(string name, Language lang)
      {
      switch (lang)
      {
      case Language.Chinese:
      Program.ChineseSpeaker(name);
      break;
      case Language.English:
      Program.EnglishSpeaker(name);
      break;
      default :
      break;
      }
      }

        但假設我們現在又要增加新的語言西班牙語,同樣我們可以增加西班牙語,但我們必須修改switch語句增加判斷,這不符合OOP中的OCP(對擴展開放,對修改關閉原則),這時候委托該登場。

      /// <summary>
      /// Define speak delegate.
      /// </summary>
      /// <param name="name"></param>
      private delegate void SpeakDelegate(string name);

        

        首先我們定義了一種委托類型SpeakDelegate,然后我們通過修改Say方法看看該如何使用委托變量。

      /// <summary>
      /// The base say function.
      /// </summary>
      /// <param name="name">The name.</param>
      /// <param name="speaker">The speaker.</param>
      private static void Say(string name, SpeakDelegate speaker)
      {
      ///Inoke the speaker function.
      speaker(name);
      }

        現在我們的參數已經不是枚舉類型了,而是一個委托類型變量,而且實現的具體代碼也沒有了switch語句了,比之前簡單了許多。現在大家知道如何去調用Say方法吧!沒錯我們只需傳遞一個name和一個具體實現函數名就OK了。

      ///傳遞函數名進行委托方法綁定
      Program.Say("鈞航", ChineseSpeaker);
      Program.Say(
      "JK.Rush", EnglishSpeaker);

        自定義委托相信大家都會了,接下來我將介紹一下.NET中委托實現,由于許多使用委托的例子都是事件,所以下面的例子也采用事件。但請大家要注意“可以使用委托,但卻沒有定義事件”的情況(例如:回調函數)。

      1.1.4 .NET中的事件委托

        舉一個簡單的例子,.NET中經常使用的控件Button,當我們把Button 控件 drap and drop到界面,然后雙擊界面的Button我們發現程序中自動生成了一個響應Button的事件方法,然后我們給事件方法添加Code之后,當我們點擊該Button就響應該方法了,但我們沒有看到代碼中有任何的委托和事件之類的定義,其實這些.NET都已經做好了。我們可以查看如下文件。

                    圖2事件委托實現

        如上圖所示我們打開Designer文件,事件委托的實現都在這里實現了。

      其中,EventHandler就是一個代理類型,可以認為它是一個“類”,是所有返回類型為void,具備兩個參數分別是object sender和EventArgs e,第一個參數表示引發事件的控件,或者說它表示點擊的那個按鈕。通過以下的代碼我們細細解析一下。

      private void button1_Click(object sender, EventArgs e)
      {
      //獲取被點擊Button的實例
      Button objBotton = sender as Button;
      if (objBotton != null)
      {
      objBotton.Text
      = "Hello you click me.";
      objBotton.AutoSize
      = true;
      }
      else
      {
      //Exception Handle.
      }
      }

       

       

       

       

       

      圖3點擊產生效果

        

        OK現在明白了sender就是傳遞一個被點擊對象的實例,第二個參數名叫e的EventArgs參數,用于      表示附加的事件關聯的事件信息。當點擊按鈕時,沒有附加任何關聯的事件信息,如上的點擊事件,第二參數并不表示任何有用的信息。但什么時候會用到呢?

        我們先介紹一下EventArgs這個的類型。其實這個類并沒有太多的功能,它主要是作為一個基類讓其他類去實現具體的功能和定義,當我們搜索EventArgs發現很多類是繼承于它的。

      public class EventArgs
      {
      // Fields
      public static readonly EventArgs Empty;

      // Methods
      static EventArgs();
      public EventArgs();
      }

        舉其中的ImageClickEventArgs為例,它繼承于EventArgs,而且還添加了自己的字段用來基類X和Y的坐標值(這是一個ImageButton被點擊時候響應的),然后獲取該按鈕的X和Y坐標。

      public sealed class ImageClickEventArgs : EventArgs
      {
      // Fields
      public int X;
      public int Y;

      // Methods
      public ImageClickEventArgs(int x, int y)
      {
      this.X = x;
      this.Y = y;
      }
      }
      //ImageButton點擊響應時間
      protected void ibtnTest_Click(object sender, ImageClickEventArgs e)
      {
      this.lblCX.Text = e.X.ToString();
      this.lblCY.Text = e.Y.ToString();
      }

       

      圖4獲取ImageClickEventArgs關聯點擊坐標

       

        前面提到其他事件關聯信息類型都是通過繼承EventArgs實現的,所以說我們自己也可以自定義一個事件關聯信息類型,如下我們只需繼承EventArgs就OK了。

      /// <summary>
      /// 自定義事件關聯類
      /// </summary>
      public class ColorChangedEventArgs : EventArgs
      {
      private Color color;

      /// <summary>
      /// Initializes a new instance of the <see cref="ColorChangedEventArgs"/> class.
      /// </summary>
      /// <param name="c">The c.</param>
      public ColorChangedEventArgs(Color c)
      {
      color
      = c;
      }

      /// <summary>
      /// Gets the color of the get.
      /// </summary>
      /// <value>
      /// The color of the get.
      /// </value>
      public Color GetColor
      {
      get { return color; }
      }

      }

      1.1.5自定義事件委托

      多播委托

        前面使用的每個委托都只包含一個方法調用。調用一個委托就調用一個方法調用。如果要通過一個委托調用多個方法,那就需要使用委托的多播特性。如果調用多播委托,就可以按委托添加次序連續調用多個方法。為此,委托的簽名就必須返回void;否則,就只能得到委托調用的最后一個方法的結果,接下來看看多播實現。

      namespace Multi_Delegate
      {
      delegate void StringProcessor();
      public class Person
      {
      private string _Name;
      public Person(string name)
      {
      this._Name = name;
      }

      public void Say()
      {
      Console.WriteLine(
      "Hello my name is {0}, what's your name.\n", this._Name);
      }

      public void Reply()
      {
      Console.WriteLine(
      "Hello my name is {0} and nice to meet you.\n", this._Name);
      }
      }

      class Program
      {
      static void Main(string[] args)
      {
      Person Jack
      = new Person("Jack");
      Person Oliver
      = new Person("Oliver");
      StringProcessor sp
      = null;
      //綁定多播方法調用
      sp += Jack.Say;
      sp
      += Oliver.Reply;
      sp();
      Console.ReadKey();
      }
      }
      }

        也許有人覺得很簡單,實現的確簡單明了,就是通過“+”把方法調用綁定到委托變量中,如果我們用“-”就可以移除綁定到委托變量方法了。

       事件

        前面一直沒有解釋什么是事件,現在讓我用一句話解釋事件和委托的關系吧!

        事件和委托關系就像是屬性和字段的關系,為了剛好的實現OOP的編程原則,事件對委托進行了封裝。

        現在我們修改前面的代碼,使用事件對委托進行封裝。

      /// 使用事件對委托進行封裝
      /// </summary>
      public class Say
      {
      /// <summary>
      /// 封裝委托字段
      /// </summary>
      public static event SpeakDelegate speakDelegate;

      /// <summary>
      /// 調用委托具體實現方法
      /// </summary>
      /// <param name="name"></param>
      public static void SayManager(string name)
      {
      speakDelegate(name);
      }
      }


      /// <summary>
      /// 客戶端調用委托
      /// </summary>
      /// <param name="args"></param>
      static void Main(string[] args)
      {
      Say.speakDelegate
      += Program.ChineseSpeaker;
      Say.speakDelegate
      += Program.EnglishSpeaker;
      Say.SayManager(
      "Jackson");
      Console.ReadKey();
      }

      圖5自定義委托

       

        現在讓我們看看編譯后Say類就可以充分證明我們的結論:事件是對委托封裝。

       

      圖6自定義事件編譯后的代碼

       

        大家看到在編譯后的代碼中出現了一個私有的委托變量,然后接下是一個公用事件委托變量,這進一步說明了事件是對委托的封裝。

       

      圖7自定義事件編譯后MSIL代碼

       

      1.1.6事件委托實現觀察者模式

        前面我們介紹按鈕事件響應是從發送者和接收者的角度出發的,現在我們以設計模式中的觀察者模式為例。

      圖8GoF觀察者架構

      namespace GoFObserver
      {
      /// <summary>
      /// 充當Subject角色
      /// </summary>
      public class GofTelecom
      {
      public delegate void GofNews();
      public static event GofNews NewEvent;

      /// <summary>
      /// 發布通知方法
      /// </summary>
      /// <returns></returns>
      public static bool Notify()
      {
      if (NewEvent != null)
      {
      NewEvent();
      return false;
      }
      return true;
      }
      }

      public interface IObserver
      {
      void Update();
      }

      /// <summary>
      /// 觀察者
      /// </summary>
      public class Programmer : IObserver
      {

      #region IObserver 成員

      public void Update()
      {
      Console.WriteLine(
      "I am a greenhand programmer.\n");
      }

      #endregion

      }

      /// <summary>
      /// 觀察者
      /// </summary>
      public class Architect : IObserver
      {
      #region IObserver 成員

      public void Update()
      {
      Console.WriteLine(
      "OH...I am a top banana.\n");
      }

      #endregion
      }



      public class Program
      {
      static void Main(string[] args)
      {
      IList
      <IObserver> objObserver = new List<IObserver>();
      objObserver.Add(
      new Programmer());
      objObserver.Add(
      new Architect());
      foreach (IObserver ob in objObserver)
      {
      GofTelecom.NewEvent
      += ob.Update;
      }

      if (!GofTelecom.Notify())
      {
      Console.WriteLine(
      "Notify successful.\n");
      }
      else
      {
      Console.WriteLine(
      "Notify failed.\n");
      }
      Console.ReadKey();
      }
      }
      }
      posted @ 2011-04-23 19:08  JK_Rush  閱讀(34206)  評論(34)    收藏  舉報
      主站蜘蛛池模板: 欧美丰满熟妇hdxx| 国产女人18毛片水真多1| 亚洲国产精品综合久久2007| 老男人久久青草av高清| 中文激情一区二区三区四区| 色狠狠色婷婷丁香五月| 国产av无码专区亚洲av软件| 亚洲最大成人av在线天堂网| 国产成AV人片在线观看天堂无码| 乐都县| 一区二区三区四区五区自拍| 久久蜜臀av一区三区| 亚洲色精品VR一区二区三区| 元朗区| 久久夜色精品国产亚洲av| 少妇人妻偷人精品系列| 欧美老熟妇喷水| 九九热在线免费视频精品| 日韩有码中文字幕av| 在线成人精品国产区免费| 国产精品一区二区久久精品| 国产av精品一区二区三区| 被灌满精子的少妇视频| 国产精品揄拍100视频| 99精品日本二区留学生| 国产精品亚洲综合第一页| 在线a人片免费观看| 久久精品国产亚洲αv忘忧草 | 国产精品一区二区不卡91| 亚洲国产精品久久久久4婷婷| 日韩中文字幕人妻精品| 亚洲综合av男人的天堂| 国产成人午夜福利高清在线观看| 少妇人妻真实偷人精品| 色综合 图片区 小说区| 91青青草视频在线观看的| 无码专区 人妻系列 在线| 精品久久综合日本久久网| 國产AV天堂| 婷婷99视频精品全部在线观看| 国产剧情福利一区二区麻豆|