關於接口是值類型還是引用類型的猜測


      雖然工作也有幾年時間了,但時常能暴露出基礎知識薄弱的問題,因此,有空閑時間時總喜歡把缺下的功課補齊。

      今天想討論的是,接口到底是引用類型還是值類型。

      要想說清楚接口到底是引用類型還是值類型,就需要先解釋一下值類型跟引用類型。

      值類型,簡單理解就是繼承自ValueType的類型,除過可空類型(如int?,bool?)外,值不能為null,通常情況下存儲在棧中。而引用類型不從ValueType繼承,其值可以為null,存儲在托管堆中,由GC負責清理。

      既然大致了解了什么是值類型和引用類型,或者說,值類型和引用類型的區別,那么有一個簡單粗暴的辦法判定接口類型問題----可以調用Object的實例方法GetType(),得到Type實例。通過Type的實例屬性BaseType,直接判斷接口的基類型。只是,接口可以理解成一種抽象類型,抽象類型是不允許實例化的,只能由實現類實例化。值類型以及引用類型都可以實現接口,所以通過基類型的方法並非個好方法。

      偶然間發現一段代碼:

  const int i = 5;

  IFormattable ftt = i;

  這里不得不提到另一對概念,裝箱和拆箱。裝箱會將值類型經過一系列包裝放到一個箱子,轉換為引用類型,然后存放到托管堆上面。拆箱和這個過程相反,從托管堆上面拿到這個箱子,經過一些列的拆分操作,從引用類型轉換成值類型。當然,拆箱過程涉及類型檢查,這里不細說。總之,裝箱可以簡單理解為值類型-->引用類型,拆箱可以簡單理解為引用類型-->值類型。有了這些理解就夠了。

  再來觀察上面的代碼段,i 為int類型,int類型是系統自定義的值類型。IFormattable是接口類型,如果接口類型是值類型,那么IFormattable ftt = i 是值類型到值類型的轉換,將不存在裝箱操作。如果接口類型是引用類型,那么IFormattable ftt = i 必然存在從值類型到引用類型的轉換,即裝箱操作。那就不多說了,采用IL查看工具看下源碼就明白了!

  

using System;

namespace Interview
{
    class TestInterfaceType
    {
        public void Test()
        {
            const int i = 5;
            IFormattable ftt = i;
        }
    }
}
Source Code

  上面是源碼,下面是IL源碼(可以通過ILSpy、Reflactor或者VS 自帶的ILDasm工具查看IL代碼):

.method public hidebysig 
    instance void Test () cil managed 
{
    // Method begins at RVA 0x2330
    // Code size 9 (0x9)
    .maxstack 1
    .locals init (
        [0] class [mscorlib]System.IFormattable ftt
    )

    IL_0000: nop
    IL_0001: ldc.i4.5
    IL_0002: box [mscorlib]System.Int32
    IL_0007: stloc.0
    IL_0008: ret
} // end of method TestInterfaceType::Test
IL Code

  亮點在於 IL_0002: box [mscorlib]System.Int32 這一行,其中 box 就代表裝箱指令。基本就可以斷定,接口屬於引用類型了。

  當然,這些只是個人的一些理解,如果有不妥的地方,歡迎各位指正。


           


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM