摘 要數據庫
.NET Framework 究竟是什麼?公共語言運行時和 .NET Framework 類庫分別指的是什麼東西?CLR、 CLS、 CTS、FCL等這些又是什麼?爲何出現程序集的概念?它與動態連接庫的區別是什麼?什麼是強命名程序集?如何簽名及部署程序集?這一章將幫助您學習和了解其中的祕密。編程
第一節 .NET Framework是什麼?緩存
.NET Framework(.NET框架),是由微軟提出並實施的一個集成在Windows中的組件。它基於虛擬機技術實現的平臺無關性的軟件開發平臺,它以語言運行庫(CLR)爲平臺支持多種語言開發,如C#、VB、託管C++等,以強制的類型安全爲基礎實施運行在託管環境中來達到代碼安全和隔離運行、提供對內存的自動化管理、線程的優化切換、提供一個統一的面向對象編程模型。安全
.NET Framework環境服務器
.NET Framework 包含兩大核心組件:公共語言運行時和.NET Framework類庫。數據結構
第二節 公共語言運行時架構
公共語言運行時 英文名Common Language Runtime,簡稱 CLR。它是一個相對開放的運行平臺,可供多種語言(C#、VB等)使用的運行時。CLR擁有一組核心功能,包括:內存管理、線程執行、程序集加載、異常處理、強制類型安全等,這些功能對全部面向CLR的語言都支持。在程序運行的時候,CLR對編碼語言是未知的,不管任何語言,只要它的編譯器是面向CLR的就能夠。像微軟本身的C#編譯器、VB編譯器、F#編譯器等。固然你也能夠實現本身的編譯器,但你的編譯器必須是面向CLR的。編譯器將對源代碼進行語法驗證和分析,最終生成託管模塊(Managed Module),進而一個傳說中的程序集誕生了。併發
託管模塊 是一個標準Microsoft Windows可移植執行體,它多是32位(PE32)文件,也多是64位(PE32+)文件。託管模塊有以下幾部分組成:框架
PE32/PE32+ 頭 標準的 Windows PE文件頭。若是文件頭使用PE32格式,則此文件只能在Windows 的32位或64位版本上運行;若是文件頭使用PE32+格式,則此文件只能在Windows 的64位版本上運行。另外,文件頭還可能包含與本地CPU代碼相關的信息。編譯器在編譯時,可經過編譯平臺/platform開關來指定該程序集包含一個PE32頭或PE32+頭。在Visual Studio中能夠對目標平臺進行選擇,如圖:
CLR頭 包含了標誌此模塊爲一個託管模塊的基本信息,如CLR版本、託管模塊入口方法、模塊的元數據、資源等。
元數據 元數據是一組數據表,它是一個二進制塊。包含三類數據表:一個表描述了與此模塊對應的源代碼中定義的類型、成員,這是定義表;另外一個表描述了此代碼所引用的其餘類型(成員)列表,這是引用表,還有一類是清單表。常見的元數據定義表有ModuleDef、TypeDef、MethodDef、FieldDef、ParamDef、PropertyDef、EventDef。常見的引用表有AssemblyRef、ModuleRef、TypeRef、MemberRef。
IL代碼 也是中間語言。編譯器編譯源代碼時生成的中間代碼,在執行環境中,這些IL代碼將被CLR的JIT編輯器翻譯成CPU能識別的指令,供CPU執行。
在執行時,CLR是經過程序集與託管模塊進行溝通的。程序集是一個或多個託管模塊和資源文件的邏輯分組,(它就至關於一個省份組織,它劃分了一部分人和地域資源)。程序集是由編譯器生成,最終生成的多是EXE或DLL文件。在程序集內有一個清單,其描述了程序集內的文件列表,如託管模塊、jpeg文件、XML文件等。CLR可以經過程序集內模塊中的自描述信息來肯定要執行此程序集中代碼時所依賴的其餘對象。
動態連接庫(Dynamic-Link Libraries,簡稱DLLs),就是一個可執行模塊,其擴展名爲.dll,它是基於C++,Delphi等語言生成的。模塊中包含了能夠被其餘應用程序或其餘dll使用的例程和資源。dll沒有一般的主程序,但它有多個執行入口。DLLs的特色在於它的代碼是在運行期動態地連接到調用它的程序中的。
.NET Framework中的 程序集的擴展名dll與動態連接庫中的dll無非是同名罷了,是徹底不相同的兩個概念。
下面以一個控制檯程序來模擬CLR加載及程序運行過程。示例代碼:
View Code
(1)在Windows中要運行一個EXE文件,Windows會首先檢查這個EXE文件的頭,以肯定該文件是32位、64位仍是WoW64(Windows on Windows64技術,運行32位程序運行在64位版本的Windows環境中),進而建立相應的進程,而後在進程的地址空間中加載MSCorEE.dll的相應x86、x64、IA64版,緊接着進程的主線程調用MSCorEE.dll中的一個CorBindToRuntimeEx函數,這個函數的主要功能就是加載CLR。CorBindToRuntimeEx函數定義:
HRESULT CorBindToRuntimeEx (
[in] LPWSTR pwszVersion,
[in] LPWSTR pwszBuildFlavor,
[in] DWORD startupFlags,
[in] REFCLSID rclsid,
[in] REFIID riid,
[out] LPVOID* ppv
);
pwszVersion 描述要加載的 CLR 的版本。
pwszBuildFlavor 字符串,指定是加載 CLR 的服務器版本仍是工做站版本。值:svr 和 wks。
startupFlags。STARTUP_FLAGS 枚舉值的組合。這些標誌控制併發垃圾回收、非特定於域的代碼以及 pwszVersion 參數的行爲。若是未設置標誌,則默認值爲一個域。
rclsid 實現ICorRuntimeHost 接口的 coclass 的 CLSID。支持的值爲 CLSID_CorRuntimeHost或 CLSID_CLRRuntimeHost。
Riid 請求自 rclsid 接口的 IID。支持的值爲 IID_ICorRuntimeHost 或 IID_ICLRRuntimeHost。
Ppv 返回的指向 riid 的接口指針。
(2)CLR加載完成後,在執行Main方法前CLR會檢查Main 方法所引用的全部類型且在內部初始化一個數據結構來記錄被引用類型的內的每一個方法的入口。因爲程序集內包含了元數據和IL,接下來CLR的主要工做就是要先找到WriteLine方法的IL,用JIT編譯器對其進行驗證(Verification),把IL翻譯成本地CPU指令,指令被保存在動態內存中。接着進行壓棧,執行第一個WriteLine方法。若是下次要再次執行WriteLine方法,因爲第一次已經對該方法進行驗證及編譯(CPU指令),因此此次直接執行CPU指令便可。因此一個類型或方法,只有在第一次執行時有性能損失,之後對該類型的調用是直接運行CPU指令,性能飛速提升。
第三節 .NET Framework類庫
Framework 類庫 英文名 Framework Class Library 簡稱 FCL。是一組與CLR緊密集成的可重用的面向對象的類型(程序集)集合。它包含有成千上萬個能使咱們的託管代碼從中導出的類型。它不只提供了一些常見的編程功能,如字符串處理,數據庫鏈接等,還提供了一些高級開發,如線程同步,反射,垃圾回收等功能;它不只公開了一些UI庫,如Windows from 、Web窗體、Silverlight等,還公開了一些面向服務的編程,如WebService,、Windows 服務、WCF等。
因爲類庫提供了太多的類型,因此它們以命名空間爲組織劃分到不一樣的dll中。例如:
System命名空間 包含了每一個應用程序都要用到的全部基本類型。
System.IO命名空間 包含了執行流I/O 以及目錄瀏覽的類型等。
基類庫 英文名 Base Class Library 簡稱BCL。它封裝了大量的基礎功能,如文件操做、圖形操做、網絡鏈接、XML文檔解析、安全加密,等等。
第四節 通用類型系統
因爲在執行時CLR對它支持的語言未知,(固然,這些語言必須是面向CLR)即CLR無論要執行的代碼是 C# 編寫仍是VB編寫。CLR圍繞類型展開,只要其編碼語言是面向CLR的,它們就能夠相互交流,要想達到相互認識和理解,必須制定類型的定義和行爲及狀態。這個對類型的定義和行爲的描述就是通用類型系統。英文名Common Type System 簡稱CTS。
CTS規定一個類型能夠包含零個或多個成員,這些成員包括:字段,屬性,方法,事件等,另外還能夠對成員的訪問規則進行控制,如public ,private,internal等。
第五節 通用語言規範
公共語言規範 英文名Common Lahguage Specification 簡稱 CLS。
CLR集成支持了全部面向CLR的語言,容許在一種語言中使用另外一種語言建立的對象,但因爲各類語言自己的特性,好比有些語言不支持無符號整數,有些不區分大小寫。若是要想作到本身公開的類型能被其餘語言所識別,則就要儘量按照其餘語言所支持的特性且本身也支持的特性去構造。CLS詳細定義了一個各類面向CLR共有的最小功能集。如圖:
第六節 通用語言基礎架構
通用語言基礎架構(Common Language Infrastructure,簡稱CLI)是一個開放的技術規範。維基百科解釋:定義了構成.NET Framework基礎結構的可執行碼以及代碼的運行時環境的規範,它定義了一個語言無關的跨體系結構的運行環境,這使得開發者能夠用規範內定義的各類高級語言來開發軟件,而且無需修正便可將軟件運行在不一樣的計算機體系結構上。
CLI有時候會和CLR混用。但嚴格意義上說,這是錯誤的。由於CLI是一種規範,而CLR則是對這種規範的一個實現。
第七節 強命名程序集及部署
在通過編譯器生成程序集後,若是隻是一個應用程序使用該程序集,則直接將該程序集複製到目標目錄便可,這就是私有程序集的部署。若是一個程序集有多個程序使用,則須要把這個共用的程序集放到一個公共的目錄。像全局應用程序域裏的程序集就是公用的。可是,若是有多個部門或公司開發的具備相同名稱的程序集放到同一個目錄,這就可能不太現實,由於後來部署上去的DLL會覆蓋先前一次部署的DLL,很顯然以文件名來區分程序集是不可取的。CLR必須提供對程序集進行惟一性驗證辦法。這就是「強命名程序集」。一個強命名程序集用四個屬性共同對一個程序集進行標識,這四個屬性是:文件名(不包括擴展名)、版本號、語言文化特性和一個公鑰(使用公鑰派生出的一個小的Hash 值,公鑰標記)。以下一個程序集文件:
「commonTypes,Version=2.0.2.1029,Culture=neutral,PublicKeyToken=c55b39c999a8888d」
強命名程序集能夠防被篡改,也能夠將強命名程序集部署到全局程序集緩存。
(1)使用SN生成密鑰,命令行導航到VS安裝目錄,使用SN命令便可生成一個密鑰,以下:
(2)將已經生成的MyApp.snk複製到項目工程下,以下圖,固然也能夠放到其餘目錄:
(3) 設置項目的屬性簽名
(4) 從新生成項目便可獲得具備強命名的程序集。
(5) 若是一個程序集是由多個應用程序使用,必須把它部署到一個讓CLR能檢測到的已知目錄,那這個目錄就是全局程序集緩存GAC。.NET4.0的GAC位於:
C:\Windows\Microsoft.NET\Assembly
必須使用GACUtil.exe工具來完成程序集的部署工做。該命令有兩個重要的開關:
/i 將某個程序集安裝到全局程序集緩存中
/u 將某個程序集從全局程序集緩存中卸載
安裝示例:載該程序集。如:
<codeBase
version="2.0.0.0" href="http://www.roojune.com/MyApp.dll"/>
gacutil /i 強命名程序所在的絕對路徑
例如:D:\>gacutil /i C:\MyApp.dll
除了將強命名程序集部署到GAC之外,還能夠以私有方式部署程序集,例如將其部署到網絡上,在config中配置當程序運行時再加。