.NET 體系結構


 

文/玄魂

本文基於.NET 4.0從整體上論述.NET框架體系結構,從新角度對安全相關比較密切地方進行介紹。由於本書性質不同於編程類教程,許多細節問題只能簡略概括或者略掉不講,有疑惑讀者還望多多見諒並查找相關資料自行修煉。

本文從.NET安全需要出發,主要介紹公共語言運行庫CLR)、公共類型系統(CTS)、公共語言規范(CLS)、中間語言(IL)、框架類庫(FCL)、基礎類庫(BCL)、即時編譯(JIT)和預編譯,以及動態語言運行時(DLR),從底層進行詳細地解析。

1.1公共語言運行時

公共語言運行時Common Language RuntimeCLR)為.NET Framework提供托管運行環境,它負責運行托管代碼,進行安全檢查,垃圾回收等。本節對運行庫進行概述,與安全相關詳細內容將會在后續章節進行詳細剖析。

微軟公司為開發人員開發由CLR負責運行程序創造非常便利條件,開發工具及編譯器不斷升級,豐富文檔詳細地介紹.NET開發方方面面。使用基於CLR語言編譯器開發代碼稱為托管代碼。托管代碼具有許多優點,例如跨語言集成、跨語言異常處理、增強安全性、版本控制和部署支持、簡化組件交互模型、調試和分析服務等。

若要使CLR能夠向托管代碼提供服務,語言編譯器必須生成一些元數據來描述代碼中類型、成員和引用。元數據與代碼一起存儲;每個可加載CLR可移植執行 (Portable ExecutablePE) 文件都包含元數據。CLR使用元數據來完成以下任務:查找和加載類、在內存中安排實例、解析方法調用、生成本機代碼、強制安全性,以及設置運行時上下文邊界。

CLR自動處理對象布局並管理對象引用,當不再使用對象時釋放它們。按這種方式實現生存期管理對象稱為托管數據。如果編寫代碼是托管代碼,可以在.NET Framework應用程序中使用托管數據、非托管數據,或者同時使用這兩種數據。由於語言編譯器會提供自己類型(如基元類型),因此可能並不總是知道(或需要知道)這些數據是否是托管

CLR,就可以很容易地設計出對象能夠跨語言交互組件和應用程序。也就是說,用不同語言編寫對象可以互相通信,並且它們行為可以緊密集成。例如,可以定義一個類,然后使用不同語言從原始類派生出另一個類或調用原始類方法,還可以將一個類實例傳遞到用不同語言編寫另一個類方法。這種跨語言集成之所以成為可能,是因為基於CLR語言編譯器和工具使用由CLR定義通用類型系統,而且它們遵循CLR關於定義新類型以及創建、使用、保持和綁定到類型規則。

所有托管組件都帶有生成它們所基於組件和資源信息,這些信息構成元數據一部分。CLR使用這些信息確保組件或應用程序具有它所有所需內容指定版本,這樣就使代碼不太可能由於某些未滿足依賴項而發生中斷。注冊信息和狀態數據不再保存在注冊表中(因為在注冊表中建立和維護這些信息很困難)。取而代之是,有關定義類型(及其依賴項)信息作為元數據與代碼存儲在一起,這樣大大降低組件復制和移除任務復雜性。

語言編譯器和工具公開CLR功能方式對於開發人員來說不僅有用,而且很直觀。這意味着,CLR某些功能可能在一個環境中比在另一個環境中更突出,對CLR體驗取決於所使用語言編譯器或工具。

1.2公共類型系統

眾所周知,每一種編程語言都有自己類型系統,但稍微接觸過不同語言讀者都會發現,各種語言類型系統都有許多相同或相似地方。.NET利用各種語言相近特性抽象出完整一套公共類型系統(CTS),使所有類型獨立於編寫它們源代碼語言。CTS構成.NET框架公共語言運行時基礎,其中最重要體現就是.NET平台多語言支持,而運行於.NET平台每一種語言又為維護自己語法特色,便使用別名來代替.NET基礎數據類型。CTS引入解決許多由多語言協作開發各個模塊所帶來問題。

1.2.1       CTS基本結構

CTS不僅定義所有數據類型,並提供面向對象模型以及各種語言需要遵守標准。CTS可以分為兩個大類:值類型和引用類型,同時這兩種類型之間還可以進行強制轉換,從值類型到引用類型轉換稱為Boxing(裝箱),從引用類型到值類型轉換稱為UnBoxing(拆箱)。

CTS基本結構如圖1-1所示,CTS每一種類型都是對象,並繼承自一個基類System.Object

 

 

1-1 CTS基本結構

1.       值類型和引用類型

值類型(Value Type)直接包含它們數據,值類型實例分配在堆棧。由上圖可知,值類型主要包括簡單類型、結構體類型和枚舉類型等。

引用類型(Reference Type實例分配在托管堆(Managed Heap)上,變量保存實例數據內存引用。由圖1-1可知,引用類型可以是自描述類型、指針類型或接口類型。而自描述類型可以進一步細分成數組和類類型。類的類型則可以是用戶定義類、裝箱值類型和委托。

2.       裝箱和拆箱

上文已經提到,所謂“裝箱”就是將值類型轉換為引用類型,所謂“拆箱”就是將被裝箱而成引用類型轉換為原來值類型。代碼清單1-1演示最簡單裝箱和拆箱。

 代碼清單1-1 裝箱和拆箱

using System;
class sample1
http://www.cnblogs.com/Images/dot.gif

public static void Main()  http://www.cnblogs.com/Images/dot.gif

int i=10;  

object obj=i;    

Console.WriteLine(i+","+(int)obj);  

}
}

下面通過Main()方法IL代碼來簡要分析這段代碼中裝箱與拆箱,如代碼清單1-2所示。關於IL代碼更多信息將在1.3節做詳細介紹。

代碼清單1-2  裝箱和拆箱IL代碼

.method public hidebysig static void  Main() cil managed

{

  .entrypoint

  // Code size       45 (0x2d)

  .maxstack  3

  .locals init ([0] int32 i,

           [1] object obj)

  IL_0000:  nop

  IL_0001:  ldc.i4.s   10

  IL_0003:  stloc.0

  IL_0004:  ldloc.0

  IL_0005:  box        [mscorlib]System.Int32

  IL_000a:  stloc.1

  IL_000b:  ldloc.0

  IL_000c:  box        [mscorlib]System.Int32

  IL_0011:  ldstr      ","

  IL_0016:  ldloc.1

  IL_0017:  unbox.any  [mscorlib]System.Int32

  IL_001c:  box        [mscorlib]System.Int32

  IL_0021:  call       string [mscorlib]System.String::Concat(object,

                                                              object,

                                                              object)

  IL_0026:  call       void [mscorlib]System.Console::WriteLine(string)

  IL_002b:  nop

  IL_002c:  ret

} // end of method sample1::Main   

 查看裝箱和拆箱次數最簡單方法就是數一數“box”和“unbox”指令出現次數。可以看出,代碼清單1-2中一共執行三次裝箱和一次拆箱操作。第一次“object obj=i;”將i裝箱;而Console.WriteLine方法用參數是String類型,String是引用類型,因此,“i+","+(int)obj”中,i需要進行一次裝箱(轉換成String類型)(int)objobj對象拆箱成值類型,而根據WriteLine方法,再次將((int)obj)值類型裝箱成引用類型。

裝箱和拆箱是有性能損失,因此在通常情況下要盡可能避免裝箱和拆箱操作。

1.2.2       公共語言規范

CLR集成很多種語言,並讓它們之間可以相互訪問,這是因為CLR建立標准類型集、元數據、公共執行環境。但由於各種語言間存在着極大差別(如區分大小寫,有不支持unsigned、操作符重載或者參數可變方法),所以要想創建這種讓別語言都能訪問程序,自己所用編程語言只能使用其語言都支持那些特性。為幫助們更好地做到這一點,Microsoft定義一個“公共語言規范”(Common Language SpecificationCLS)

CLS定義CTS子集,通過定義一組開發人員可以確信在多種語言中都可用功能來增強和確保語言互用性。CLS還建立CLS遵從性要求,這幫助確定托管代碼是否符合CLS以及一個給定工具對托管代碼(該代碼是使用CLS功能)開發支持程度。

 如果組件在對其代碼(包括派生類)公開API中只使用 CLS功能,那么可以保證在任何支持 CLS編程語言中都可以訪問該組件。遵守CLS規則、僅使用CLS所包含功能組件叫做符合 CLS組件。

如圖1-2所示,CLR/CTS提供一個組特性,一些語言會提供這些特性一個較大子集(IL提供全部特性)。而CLS是每種語言必須支持一個最小特性集合。

 

 

1-2 CTSCLS關系

如果一種語言定義一個類型,並希望在另一種語言中使用該類型,就絕對不能在該類型公共和受保護成員中使用CLS外部任何特性。否則其編程人員使用其語言來編寫代碼時,就可能無法訪問該類型成員。代碼清單1-3簡單地演示遵從CLS兼容性代碼編寫。

代碼清單1-3  CLS兼容性示例

using System;

 //告訴編譯器檢查CLS相容特性

 [assembly: CLSCompliant(true)]

 namespace SomeLibrary

{

    //開始出現警告,因為類是公有

    public sealed class SomeLibraryType

    {

        //警告,返回值不符合CLS

        public UInt32 Abc()

        {

            return 0;

        }

        //警告,僅大小寫不同不符合CLS

        public void abc()

        {

        }

        //沒有錯誤,該方法是私有

        private UInt32 ABC()

        {            return 0;

        }   

}

}

如果將上述代碼中SomeLibraryType修飾符public去掉話,一切警告也就消失,因為這樣該類將使用默認修飾符internal,所以在程序集外部不可見。

注意  不能把類SomeLibraryType修飾符public改成privateprotectedprotected internal任何一個,因為命名空間中定義元素無法顯式聲明為 privateprotected protected internal

關於CLS詳細內容請讀者參考MSDN文檔及相關資料。

-------------------------------------注:本文改編自 《.NET 安全揭秘》1.1、1.2節

 

 


免責聲明!

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



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