本文基於.NET 4.0從整體上論述.NET框架的體系結構,從新的角度對安全相關比較密切的地方進行介紹。由於本書的性質不同於編程類教程,許多細節問題只能簡略概括或者略掉不講,有疑惑的讀者還望多多見諒並查找相關資料自行修煉。
本文從.NET安全的需要出發,主要介紹公共語言運行庫(CLR)、公共類型系統(CTS)、公共語言規范(CLS)、中間語言(IL)、框架類庫(FCL)、基礎類庫(BCL)、即時編譯(JIT)和預編譯,以及動態語言運行時(DLR),從底層進行詳細地解析。
1.1公共語言運行時
公共語言運行時(Common Language Runtime,CLR)為.NET Framework提供了托管運行環境,它負責運行托管代碼,進行安全檢查,垃圾回收等。本節對運行庫進行概述,與安全相關的詳細內容將會在後續章節進行詳細剖析。
微軟公司為開發人員開發由CLR負責運行的程序創造了非常便利的條件,開發工具及編譯器不斷升級,豐富的文檔詳細地介紹了.NET開發的方方面面。使用基於CLR的語言編譯器開發的代碼稱為托管代碼。托管代碼具有許多優點,例如跨語言集成、跨語言異常處理、增強的安全性、版本控制和部署支持、簡化的組件交互模型、調試和分析服務等。
若要使CLR能夠向托管代碼提供服務,語言編譯器必須生成一些元數據來描述代碼中的類型、成員和引用。元數據與代碼一起存儲;每個可加載的CLR可移植執行 (Portable Executable,PE) 文件都包含元數據。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
{
public static void Main()
{
int i=10;
object obj=i;
Console.WriteLine(i+","+(int)obj);
}
}
下面通過Main()方法的IL代碼來簡要分析這段代碼中的裝箱與拆箱,如代碼清單1-2所示。關於IL代碼的更多信息將在1.3節做詳細介紹。
查看本欄目
1.2.2 公共語言規范
CLR集成了很多種語言,並讓它們之間可以相互訪問,這是因為CLR建立了標准的類型集、元數據、公共執行環境。但由於各種語言間存在著極大的差別(如區分大小寫,有的不支持unsigned、操作符重載或者參數可變的方法),所以要想創建這種讓別的語言都能訪問的程序,自己所用的編程語言只能使用其他語言都支持的那些特性。為了幫助我們更好地做到這一點,Microsoft定義了一個“公共語言規范”(CommonLanguage Specification,CLS)。
CLS定義了CTS的子集,通過定義一組開發人員可以確信在多種語言中都可用的功能來增強和確保語言互用性。CLS還建立了CLS遵從性要求,這幫助你確定你的托管代碼是否符合CLS以及一個給定的工具對托管代碼(該代碼是使用CLS功能的)開發的支持程度。
如果你的組件在對其他代碼(包括派生類)公開的API中只使用了CLS功能,那麼可以保證在任何支持CLS的編程語言中都可以訪問該組件。遵守CLS規則、僅使用CLS所包含功能的組件叫做符合CLS的組件。
如圖1-2所示,CLR/CTS提供了一個組特性,一些語言會提供這些特性的一個較大子集(IL提供全部特性)。而CLS是每種語言必須支持的一個最小特性集合。
圖1-2 CTS與CLS的關系
如果一種語言定義了一個類型,並希望在另一種語言中使用該類型,就絕對不能在該類型的公共和受保護的成員中使用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改成private、protected或protectedinternal中的任何一個,因為命名空間中定義的元素無法顯式聲明為private、protected 或 protected internal。
作者:玄魂
出處:http://www.cnblogs.com/xuanhun/