從IL代碼角度分析C#的【事件】與【委託】的區別

來源:互聯網
上載者:User

 

event與delegate的區別
首先,通過加入event關鍵字,在編譯的時候編譯器會自動針對事件產生一個私人的欄位(與此事件相關的委託),以及兩個訪問器方法,即add訪問器方法以及remove訪問器方法,用於對事件的註冊及登出(對事件使用+=及-=操作時就是調用的這兩個方法)。
我想你們的問題主要是,實際上聲明一個委託類型的欄位也可以實現這些功能。
實際上之所以採用event而不直接採用委託,實際上還是為了封裝。可以設想一下,如果直接採用公用的委託欄位,類型外部就可以對此欄位進行直接的操作了,比如將其直接賦值為null。
而使用event關鍵字就可以保證對事件的操作僅限於add訪問器方法以及remove訪問器方法(即只能使用+=及-=)

event與delegate是C#中的兩個關鍵字,在微軟的常式中常見它們一起出現,那麼他們之間有什麼關係呢?

想看專業的解釋就看:
.NET Famework SDK文檔-〉參考-〉編譯器和語言參考-〉C#-〉C#語言規範-〉10.7.1類似欄位的事件
裡面有詳細的解釋。
這裡我想就編譯時間發生的事情做一下描述。

上面的參考中有一句:“引發一個事件”與“調用一個由該事件表示的委託”完全等效。
什麼意思呢?
我覺得可以這樣表述:事件的引發是通過調用委託實現的,而委託不僅僅可以用來實現事件的引發。
我寫了下面一段測試代碼,我們可以看看編譯器到底對event做了些什麼。

我們用ildasm工具開啟產生的IL代碼:


可以看到delegate abc實際上是從MulticastDelegate繼承而來的一個類。
而在我們自己聲明的thisevent事件、d()、e()方法之外,多出了一個thisevent欄位和兩個方法add_thisevent()、remove_thisevent()。
正如上面提到的那篇參考內描述的那樣,一個事件的聲明是可以轉化為一個代理欄位的聲明加上添加、刪除兩種方法的事件操作。

我們查看thisevent事件的IL代碼:

.event test4eventil.Class1/abc thisevent
{
  .addon instance void test4eventil.Class1::add_thisevent(class test4eventil.Class1/abc)
.removeon instance void test4eventil.Class1::remove_thisevent(class test4eventil.Class1/abc)
} // end of event Class1::thisevent

 

可以看到,實際上add_thisevent()與remove_thisevent()是包含在thisevent事件中的兩個方法。

那麼,這兩個方法與delegate有什麼關係呢?
我們看看add_thisevent()的IL代碼:

.method public hidebysig specialname instance void 
       add_thisevent(class test4eventil.Class1/abc 'value') cil managed synchronized
{
// 代碼大小       24 (0x18)
  .maxstack  3
  IL_0000:  ldarg.0
  IL_0001:  ldarg.0
  IL_0002:  ldfld      class test4eventil.Class1/abc test4eventil.Class1::thisevent
  IL_0007:  ldarg.1
  IL_0008: call       class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate, class [mscorlib]System.Delegate)
  IL_000d:  castclass  test4eventil.Class1/abc
  IL_0012:  stfld      class test4eventil.Class1/abc test4eventil.Class1::thisevent
  IL_0017:  ret
} // end of method Class1::add_thisevent

反編譯後如下:

public void add_thisevent(abc value) {
   this.thisevent = (abc) Delegate.Combine(this.thisevent, value);
}

而remove_thisevent()則是:

public void remove_thisevent(abc value) {
   this.thisevent = (abc) Delegate.Remove(this.thisevent, value);
}

 

也就是說,實際上,添加一個事件的綁定,實際上就是向該事件表示的委託列表中添加一項委託。而取消一個事件的綁定,就是從委託列表中刪除一項委託。

所以,對event的綁定都是通過在delegate列表中添加、刪除項來實現的。
另外,需要注意的一點是:除了在event對象聲明的類內部,event對象只能用在+=和-=的左邊。
Comments

不錯,
效果一樣,
event通常只能被所申明的類訪問.

[url=]re: event與delegate的關係
Ninpute
你甚至可以自己寫那個add和remove方法,以求最大控制

 

re: event與delegate的關係[/url][url=]idior[/url]

public class Class1
    {
        public delegate void abc();
        public event abc thisevent;
        public Class1()
        {
            thisevent += new abc(d);
            thisevent += new abc(e);
            thisevent -= new abc(d);
            thisevent = thisevent - new abc(e);
        }

        public void d(){}
        public void e(){}
   }
謝謝轉載引用本文! 轉載時如有可能請保留以下連結, 作者將表示感謝!
原文地址:http://www.bmpj.net/forum.php?mod=viewthread&tid=1092&page=1&extra=#pid7662

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.