天天看點

C#之委托與事件委托與事件

廢話一堆:網上關于委托、事件的文章有很多,一千個哈姆雷特莎士比亞就有一千個莎士比亞,以下内容均是本人個人見解。

        這一小章來學習一下怎麼簡單的使用委托,了解一些基本的知識。

        這裡先看一下其他所要用到的類的資訊

       ///

<summary>

        /// 函數用例

        /// </summary>

        public

class ManyMethodClass

        {

            public ManyMethodClass() { }

            /// <summary>

/// 執行個體函數

            ///

</summary>

            /// <param

name="strmes"></param>

            public void

InstanceMethod(string strmes)

            {

Console.WriteLine("執行個體函數輸出:"

+ strmes);

            }

/// <summary>

          /// 靜态函數

          ///

          /// <param

          public

static void

StaticMethod(string strmes)

          {

Console.WriteLine("靜态函數輸出:"

          }

       }

定義一個委托類型

public delegate void DisplayStringDelegate(string

strmes); 

執行個體化委托類型

            //綁定執行個體函數 第一種定義方式(執行個體函數)

            DisplayStringDelegate

disstrdele_instance = new

DisplayStringDelegate(new ManyMethodClass().InstanceMethod);

            //綁定靜态函數 第二種定義方式(靜态函數)

            DisplayStringDelegate disstrdele_static

= new DisplayStringDelegate(ManyMethodClass.StaticMethod);

            //綁定委托執行個體 第三種定義方式(委托執行個體)

disstrdele_delegate = new

DisplayStringDelegate(disstrdele_instance);

調用委托執行個體

disstrdele_instance.Invoke("Hello

Word");

disstrdele_static("Hello Word");

disstrdele_delegate("Hello

(ps:這裡不同的調用方式效果都是一樣的,在下一節會有講到)

        最後讓我們看一下最終的效果圖:

C#之委托與事件委托與事件

委托類型是類類型

           ///

委托示例類

           public

class DelegateDemonStration

           {

public DelegateDemonStration()

{ }

public delegate

void DisplayStringDelegate(string strmes);

           }

在上面的示例代碼中,我們定義了一個委托示例類DelegateDemonStration,在DelegateDemonStration的内部我們定義了上一節中講到的委托的類型DisplayStringDelegate,

           在這裡先不談DisplayStringDelegate它定義簽名類型,先來談談它到底是什麼樣的存在。

           我們來看一下代碼:

public class

DisplayStringDelegate : MulticastDelegate

{

public DisplayStringDelegate(object @object, IntPtr

method){}

public virtual

IAsyncResult BeginInvoke(string

strmes, AsyncCallback callback,

object @object);

void EndInvoke(IAsyncResult

result);

void Invoke(string

strmes);

}

當我們定義好一個委托類型的時候,在運作時C#編譯器把【public

delegate void

DisplayStringDelegate(string strmes);】

           編譯為【public

class DisplayStringDelegate

: MulticastDelegate】

           是以,各位客官隻要記住

在你定義一個委托類型的時候實際上你是定義了一個類

委托執行個體是函數指針

先讓我們來看一下這一小節所要用到的示例代碼(所用到的對象類型還是上一小節的内容):

            DisplayStringDelegate disstrdele =

new DisplayStringDelegate(new ManyMethodClass().InstanceMethod);

            disstrdele

+= ManyMethodClass.StaticMethod;//這裡是委托類型推斷 綁定函數的一種方式 幾種方式可以自行百度

+= new DisplayStringDelegate(ManyMethodClass.StaticMethod);

1.第一步  在我們執行DisplayStringDelegate disstrdele =

new DisplayStringDelegate(new ManyMethodClass().InstanceMethod);的時候,disstrdele執行個體是如下圖一樣:

C#之委托與事件委托與事件

           2.第二步 當我們繼續執行代碼

disstrdele += ManyMethodClass.StaticMethod;的時候,請再來看圖:

C#之委托與事件委托與事件

這是disstrdele多指向了一個函數位址,而它的内部實作并不是外表看起來這樣簡單的:

C#之委托與事件委托與事件

這裡簡要的說一下執行第二步的時候

L_0012:是将第一步的disstrdele執行個體壓入棧中

L_0013:将一個空引用壓入棧中

           L_0014:加載ManyMethodClass.StaticMethod函數位址

           L_001a:執行個體化DisplayStringDelegate委托類型,假如它叫A

L_001f:将disstrdele和A合并

L_0024:将合并好的值轉換成DisplayStringDelegate類型,并且存入L_0013中

L_0029:将L_0013指派到disstrdele執行個體

(以上純屬個人了解,如有偏差請幫忙糾正,謝謝)

           3.第三步

當我們繼續執行代碼disstrdele += new

DisplayStringDelegate(ManyMethodClass.StaticMethod);的時候,過程和第二步相同:

C#之委托與事件委托與事件

終上所述,委托執行個體都會指向一個函數位址,當然喽合并過後新的委托執行個體甯當别論,是以 委托執行個體是函數指針 或者

委托執行個體是函數指針清單

         我們來看調用的代碼:

          disstrdele("Hello Word");

這裡的内容是接着上一小節的内容繼續講的,拆分開來講是為了讓大家能看的更清楚。

         看一下示意圖吧,

C#之委托與事件委托與事件

        從這裡就可以看出來了,雖然disstrdele

執行個體是合并後的委托執行個體,它的屁股上挂上了好多函數位址,但是執行這樣函數的入口還隻是一個,那就是Delegate.Invoke(string),

如果有人要問它的Invoke(string)内部是怎麼實作的,暫時回答不了,因為具體的代碼是動态生成的吧,不過我們可以自己猜想或者想象一下它是怎麼實作的。

        在這裡就不多說了。

       看了以上的内容能大概的知道或者厘清一些概念性的東西。

這裡本人隻是講了一把劍是由鐵鑄成的,可以用來切割、刺、劈、砍,至于這把劍怎麼用就因人而異了。

       這一章我們來學習一下事件

照舊我們先來看一下示例代碼:

      public class

EventDomeStration

       {

            public EventDomeStration() { }

定義好的一個示例

            public event

DisplayStringDelegate

DisplayStringEventHandler;

        }

在上面的代碼中,我們定義了一個事件DisplayStringEventHandler,而在它名稱前面的是一個DisplayStringDelegate委托類型(就是我們上一節所說的委托)。

        就對于它而言來看一下MSIL,看看它究竟是什麼樣的:

        .class public auto ansi

beforefieldinit EventDomeStration extends [mscorlib]System.Object

         {

.field private class DelegateCaseAndEventCase.DisplayStringDelegate

DisplayStringEventHandler

.event DelegateCaseAndEventCase.DisplayStringDelegate

.addon instance void

DelegateCaseAndEventCase.EventDomeStration::add_DisplayStringEventHandler(class

DelegateCaseAndEventCase.DisplayStringDelegate)

.removeon instance void

DelegateCaseAndEventCase.EventDomeStration::remove_DisplayStringEventHandler(class

        從這裡可以看到,定義好的一個事件就是一個私有(DisplayStringDelegate委托類型)的字段加上一個事件通路器,也就是相當于C#代碼的這樣:

class EventDomeStration

public EventDomeStration() { }

private DisplayStringDelegate

displaystringdele;

public event

DisplaystringEventHandler

add

displaystringdele += value;

remove

displaystringdele -= value;

         }

         在這裡本人對事件的定義是:

事件就是所在對象裡的屬性,而屬性的類型是委托類型,它是負責架設與外部對象即時通訊(傳遞消息)的橋梁,橋梁本身就是委托。

出門在外務工,難免要租房子住,每次找房子是件頭疼的事請各位客官一起來看一下,就拿這個來舉個例子。

         先定義一個委托:public

消息回報(string

回報房子資訊);

         首先得有一個中介,暫且叫它為房産中介1,

來看一下它的内部定義:

房産中介1

public 房産中介1() {

public 房産中介1(string

具體要求)

房源資訊處理(具體要求);

消息回報

消息通知;

public string

客戶要求的資訊_1 = string.Empty;

private void

房源資訊處理(string

客戶要求的資訊)

 //邏輯處理

 //假如是有客戶需要的

則通知客戶

  if (消息通知 != null)

 {

    消息通知("有房子,什麼樣的,資訊等等");

 }

 客戶要求的資訊_1 =

客戶要求的資訊;

 //邏輯處理要是沒有

把資訊移交給了中介2

房産中介2 中介2 = new

房産中介2(this);   

public void 其它中介消息通知(string

房子資訊)

if (消息通知 != null)

消息通知(房子資訊);

中介有了,那現在我想要開始租房子怎麼辦?沒關系,找中介。

        首先先把“我”定義出來:

class 我

//比如我要租房子

public 我(){ }

public void 我要租房子(string

具體的要求)

//找的是房産中介1

房産中介1 中介1 = new

房産中介1(具體的要求);

中介1.消息通知 += new 消息回報(中介1_消息通知);

void 中介1_消息通知(string

//我可以從【房子資訊】中知道是否有有合适的房子,如果有得話,是什麼樣的

class 房産中介2

public string 客戶要求資訊 = string.Empty;

public 房産中介2() { }

public 房産中介2(房産中介1

中介1)

房源資訊處理(中介1);

private void 房源資訊處理(房産中介1

//邏輯處理

//判斷是否有滿足 ->中介1.客戶要求的資訊_1值條件的房源

//如果有

中介1.其它中介消息通知("房子有的,房子的資訊等等");

          }

          上面定義了 我、房産中介1、房産中介2,現在

我 要找房子了

          我

me = new 我();

          me.我要租房子("有床就行");

          好了,“我”已經把資訊釋出出去了,現在就坐等房産中介1的通知了。

因為事件隻能是對象本身内部觸發,這個設計是合理,為什麼不能用委托,委托也可以實作同樣的功能啊?

假如用了委托,這個例子的意思就是“我”可以控制房産中介1有沒有找到房子資訊,這個是不符合常理的。

          因為“我”是找的房産中介1,房産中介1根據“我”的要求沒找到,把這個資訊交給了房産中介2,讓房産中介2幫忙找找,然後中房産中介2找到了,

          但是中房産中介2并不能直接通知“我”,如果可以直接通知的話,這樣“我”會告房産中介1侵犯客戶隐私,

          是以隻能是房産中介2告訴房産中介1找到了【也就是代碼:房産中介1.其它中介消息通知("房子有的,房子的資訊等等");】,然後再由房産中介1來通知“我”。

作者:

出處:

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面