亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

簡單聊聊c# 事件

 更新時間:2020年07月23日 10:29:46   作者:Learning hard  
這篇文章主要介紹了c# 事件的相關(guān)資料,文中講解非常細致,代碼幫助大家更好的理解和學習,感興趣的朋友可以了解下

引言:

前面幾個專題對委托進行了詳細的介紹的,然后我們在編寫代碼過程中經(jīng)常會聽到“事件”這個概念的,尤其是寫UI的時候,當我們點擊一個按鈕后VS就會自動幫我們生成一些后臺的代碼,然后我們就只需要在Click方法里面寫代碼就可以,所以可能有些剛接觸C#的朋友就覺得這樣很理所當然的,也沒有去思考這是為什么的,為什么點擊下事件就會觸發(fā)我們在Click方法里面寫的代碼呢?事件到底扮演個什么樣的角色呢?為了解除大家的這些疑惑,下面就詳細介紹了事件,讓一些初學者深入理解C#中的事件的概念。

一、為什么C#中會有事件的?

  前面專題中介紹了我理解的為什么需要委托的,所以這里我來分享下我理解的為什么C#中要引入事件這個概念的。下面就簡單講講生活中事件的例子的,最近我生日剛過完的,我就以生日這個話題要談?wù)劦?,日子一天天的過去,當生日的日期到的時候,這時候就觸發(fā)了生日事件的,此時過生日的人就是觸發(fā)生日事件的對象的,然后有些關(guān)系你的朋友就會對這個事件進行關(guān)注,一旦這個事件觸發(fā), 他們就可能會陪你一起慶祝生日,然后送禮物給你,當然并不是所有人都會對你的生日關(guān)注的,有些人肯定根本就不知道的, 只有對于你生日事件進行了關(guān)注了的人才會送禮物給你。這樣的生活中的一個生日過程,然而對于為什么C#中會有事件這個概念當然就更好理解了,C#是一個面向?qū)ο蟮恼Z言,我們使用C#語言進行編碼也是為了用代碼幫助我們完成現(xiàn)實生活中的事情的,所以當然也就必須有事件來反映生活中發(fā)生事情的情況了。

二、自己如何實現(xiàn)一個事件模式的?

  現(xiàn)在我們知道了為什么C#要引入事件了,但是對于我們在代碼中使用的事件大部分都是.net類庫為我們提供的,例如控件的各種事件,我們只需要點擊按鈕后就會觸發(fā)點擊事件的,但是我們很想理解這個事件是如何觸發(fā)的,我們是否可以自己定義實現(xiàn)事件模式的一個程序的呢?答案當然是可以的,下面就以上面生日的例子來通過代碼來解釋下如何實現(xiàn)一個事件模式的。

具體代碼為:

using System;
using System.Threading;

namespace BirthdayEventDemo
{
  class Program
  {
    static void Main(string[] args)
    {
      // 實例化一個事件源對象
      Me eventSource = new Me("Learning Hard");

      // 實例化關(guān)注事件的對象
      Friend1 obj1 = new Friend1();
      Friend2 obj2 = new Friend2();

      // 使用委托把對象及其方法注冊到事件中
      eventSource.BirthDayEvent+=new BirthDayEventHandle(obj1.SendGift);
      eventSource.BirthDayEvent+=new BirthDayEventHandle(obj2.Buycake);
      
      // 事件到了觸發(fā)生日事件,事件的調(diào)用
      eventSource.TimeUp();
      Console.Read();
    }
  }
  // 第一步: 定義一個類型用來保存所有需要發(fā)送給事件接收者的附加信息
  public class BirthdayEventArgs : EventArgs
  {
    // 表示過生日人的姓名
    private readonly string name;

    public string Name
    {
      get { return name;}
    }

    public BirthdayEventArgs(string name)
    {
      this.name = name;
    }
  }
  // 第二步:定義一個生日事件,首先需要定義一個委托類型,用于指定事件觸發(fā)時被調(diào)用的方法類型
  public delegate void BirthDayEventHandle(object sender, BirthdayEventArgs e);
  // 定義事件成員
  public class Subject
  {
    // 定義生日事件
    public event BirthDayEventHandle BirthDayEvent;

    // 第三步:定義一個負責引發(fā)事件的方法,它通知已關(guān)注的對象(通知我的好友)
    protected virtual void Notify(BirthdayEventArgs e)
    {
      // 出于線程安全的考慮,現(xiàn)在將對委托字段的引用復制到一個臨時字段中
      BirthDayEventHandle temp = Interlocked.CompareExchange(ref BirthDayEvent, null, null);
      if (temp != null)
      {
        // 觸發(fā)事件,與方法的使用方式相同
        // 事件通知委托對象,委托對象調(diào)用封裝的方法
        temp(this, e);
      }
    }
  }

  // 定義觸發(fā)事件的對象,事件源
  public class Me : Subject
  {
    private string name;
    public Me(string name)
    {
      this.name = name;
    }
    public void TimeUp()
    {
      BirthdayEventArgs eventarg = new BirthdayEventArgs(name);
      // 生日到了,通知朋友們
      this.Notify(eventarg);

    }
  }

  // 好友對象
  public class Friend1
  {
    public void SendGift(object sender,BirthdayEventArgs e)
    {
      Console.WriteLine(e.Name+" 生日到了,我要送禮物");
    }
  }
  public class Friend2
  {
    public void Buycake(object sender, BirthdayEventArgs e)
    {
      Console.WriteLine(e.Name + " 生日到了,我要準備買蛋糕");
    }
  }
}

運行結(jié)果為:

三、編譯器是如何解釋事件的呢?

  上面我們已經(jīng)介紹了如何去實現(xiàn)自己去實現(xiàn)一個事件模式的,大家可以展開代碼來具體的查看的,實現(xiàn)過程主要是——定義觸發(fā)對象的事件源(指的是誰過生日)->定義關(guān)注你生日事件的朋友對象-> 方法登記對事件的關(guān)注,當事件觸發(fā)時通知登記的方法被調(diào)用。然而相信大家還有有疑問——到底C#中的事件是什么呢?編譯器又是如何去解釋它的?下面就為大家解除下疑惑的:

  首先事件其實就是委托的(確切的說事件就是委托鏈),從上面的代碼中,我們定義的事件除了使用event關(guān)鍵字外,還用到了一個委托類型,然而委托是一個類,類肯定就有屬性字段的,然而我們就可以把事件理解為委托的一個屬性,屬性的返回值是一個委托類型。說事件是委托的一個屬性,是有根據(jù)的,我們通過中間語言代碼可以知道編譯器是如何去解釋我們定義的事件的。

 // 第二步:定義一個生日事件,首先需要定義一個委托類型,用于指定事件觸發(fā)時被調(diào)用的方法類型
  public delegate void BirthDayEventHandle(object sender, BirthdayEventArgs e);
  // 定義生日事件
    public event BirthDayEventHandle BirthDayEvent;

當我們像上面定義一個事件時,編譯器會把它轉(zhuǎn)換為3段代碼(大家可以通過IL反匯編程序來查看的):

// 1. 一個被初始化為null的私有委托字段
    private BirthDayEventHandle BirthDayEvent =null;

    //2. 一個公共add_BirthDayEvent方法
    public void add_BirthDayEvent(BirthDayEventHandle value)
    {
      // 以一種線程安全的方式從事件中添加一個委托
    }
    // 3. 一個公共的remove_BirthDayEvent方法
    public void remove_BirthDayEvent(BirthDayEventHandle value)
    {
      // 以一種線程安全的方式從事件中移除一個委托
    }

第一段代碼一個委托的私有字段,該字段是對一個委托列表的頭部的引用,事件發(fā)生時會通知這個列表中的委托。字段初始化為null,表明無關(guān)注人登記了對事件的關(guān)注。
第二段代碼是一個以add為前綴的方法,該方法是由編譯器自動命名的,代碼內(nèi)容調(diào)用Delegate.Combine方法將委托實例添加到委托列表中,返回新的列表地址,并將這個地址存回字段。

第三段代碼也是一個方法,它使得一個對象注銷對事件的關(guān)注,同樣的方法體調(diào)用Delegate.Remove方法將委托實例從委托列表中刪除,返回新的列表地址,并將這個地址存回字段中。(注,如果試圖刪除一個從未添加過的方法,Delegate.Remove方法在內(nèi)部將不做任何事情,也就是說,不會拋出任何一次,也不會顯示任何警告,事件的方法集合保持不變)。

同時大家也可以通過調(diào)試來說明事件是一個委托鏈的,大家可以在 eventSource.BirthDayEvent+=new BirthDayEventHandle(obj2.Buycake);這行代碼設(shè)置一個斷點調(diào)試的,下面是我調(diào)試過程中的一個截圖,大家也可以自己調(diào)試看看的,這樣將會更加理解事件是一個委托鏈的概念:

按F10運行一行后的截圖

通過上面的截圖,相信大家對于事件是一個委托鏈的概念相信會有進一步的理解的。

四、小結(jié)

  到這里本專題的內(nèi)容也就介紹完了, 希望通過本專題,大家可以對事件有進一步的理解,理解事件與委托之間的關(guān)系。這個專題通過自己實現(xiàn)的一個事件模式里解釋事件的本質(zhì),然而我們經(jīng)常使用的是Net類庫中定義好的事件,然而有些剛接觸C#的人卻不理解Net中定義的事件背后所做的事情,只是知道點下按鈕后在Click方法里面寫入自己的一些控制代碼,然而背后的過程具體是怎樣的,既然事件是委托,那么Click事件是委托類型,其中的委托類型又是怎么被實例化的呢?這些內(nèi)容將在下一個專題給大家分享下的。

以上就是簡單聊聊c# 事件的詳細內(nèi)容,更多關(guān)于c# 事件的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論