發(fā)文章
發(fā)文工具
撰寫
網(wǎng)文摘手
文檔
視頻
思維導(dǎo)圖
隨筆
相冊
原創(chuàng)同步助手
其他工具
圖片轉(zhuǎn)文字
文件清理
AI助手
留言交流
什么是CLR
CLR的基本概念
通用語言運行平臺(Common Language Runtime,簡稱CLR)是微軟為他們的.Net虛擬機(jī)所選用的名稱。這是通用語言架構(gòu)(簡稱CLI)的微軟實現(xiàn)版本,它定義了一個代碼運行的環(huán)境。CLR運行一種稱為“通用中間語言”的字節(jié)碼,這個是微軟的通用中間語言實現(xiàn)版本。 CLR運行在微軟的視窗操作系統(tǒng)上。查看通用語言架構(gòu)可以找到該規(guī)格的實現(xiàn)版本列表。其中有一些版本是運行在非Windows的操作系統(tǒng)中。(維基百科CLR)
通用語言運行平臺(Common Language Runtime,簡稱CLR)是微軟為他們的.Net虛擬機(jī)所選用的名稱。這是通用語言架構(gòu)(簡稱CLI)的微軟實現(xiàn)版本,它定義了一個代碼運行的環(huán)境。CLR運行一種稱為“通用中間語言”的字節(jié)碼,這個是微軟的通用中間語言實現(xiàn)版本。
CLR運行在微軟的視窗操作系統(tǒng)上。查看通用語言架構(gòu)可以找到該規(guī)格的實現(xiàn)版本列表。其中有一些版本是運行在非Windows的操作系統(tǒng)中。(維基百科CLR)
以上定義至少包含以下幾點信息:
CLR和.Net Framework的關(guān)系
.NET框架 (.NET Framework) 是由微軟開發(fā),一個致力于敏捷軟件開發(fā)(Agile software development)、快速應(yīng)用開發(fā)(Rapid application development)、平臺無關(guān)性和網(wǎng)絡(luò)透明化的軟件開發(fā)平臺。.NET框架是以一種采用系統(tǒng)虛擬機(jī)運行的編程平臺,以通用語言運行庫(Common Language Runtime)為基礎(chǔ),支持多種語言(C#、VB.NET、C++、Python等)的開發(fā)。(維基百科.Net Framework)
由此可見,.Net Framework是一個支持多種開發(fā)語言的開發(fā)平臺,而這種多語言支持的特性又要以CLR為基礎(chǔ)。CLR是一個.Net產(chǎn)品的運行環(huán)境。公共語言運行時(Common Language Runtime)和 .Net Framework 類庫(FCL)是.Net Framework的兩個主要組成部分。
CLR>=CLR+CLI+FCL。
目前有哪些語言支持CLR
微軟已經(jīng)為多種語言開發(fā)了基于CLR的編譯器,這些語言包括:C++/CLI、C#、Visual Basic、F#、Iron Python、 Iron Ruby和IL。除此之外,其他的一些公司和大學(xué)等機(jī)構(gòu)也位一些語言開發(fā)了基于CLR的編譯器,例如Ada、APL、Caml、COBOL、Eiffel、Forth、Fortran、Haskell、Lexicon、LISP、LOGO、Lua、Mercury、ML、Mondrian、Oberon、Pascal、Perl、PHP、Prolog、RPG、Scheme、Smaltak、Tcl/Tk。
CLR為不同的編程語言提供了統(tǒng)一的運行平臺,在很大程度上對上層開發(fā)者屏蔽了語言之間才特性差異。對于CLR來說,不同語言的編譯器(Compiler)就相當(dāng)于一個這種語言的代碼審查者(Checker),所做的工作就是檢查源碼語法是否正確,然后將源碼編譯成CLR所需要的中間語言(IL)。所以編程語言對于CLR是透明的,也就是說CLR只知道IL的存在,而不知道IL是由哪種語言編譯而來。
CLR的這種“公共語言”的特性使得“多語言混合編程”成為可能,讓APL開發(fā)人員可以使用自己熟悉的語言和語法來開發(fā)基于.Net的項目。當(dāng)然,更重要的是,這種特性允許用不同的語言來開發(fā)同一個項目的不同模塊,比如在一個項目中用Visual Basic開發(fā)UI、用APL開發(fā)財務(wù)相關(guān)的模塊,而與數(shù)學(xué)計算有關(guān)的模塊使用F#,充分利用這些語言的特性,將會得到意想不到的效果。
什么是CLS
正如上面所說,CLR集成了這些所有的語言,使得一種編程語言可以使用另一種編程語言創(chuàng)建的對象。語言集成是一個宏偉的目標(biāo),然而,一個不得不面對的事實是不同的編程語言之間存在著極大的差異,比如有些語言不支持操作符重載、有些語言不支持可選參數(shù)等等。為了保證用一種面向CLR的編程語言創(chuàng)建的對象能夠安全的被其他面向CLR的語言來訪問,最好的辦法就是在用這種語言編程的時候只是用那些所有面向CLR的語言都支持的特性。為此,微軟專門定義了一個“公共語言規(guī)范(Common Language Specification)”,即CLS。CLS定義了一個最小的功能集,任何面向CLR的編譯器生成的類型想要兼容其他“符合CLS,面向CLR”的組件,都必須支持這個最小功能集。
CLR/CTS 支持的功能比 CLS 定義的子集多得多。如果不關(guān)心語言之間的互操作性,可以開發(fā)一套功能非 常豐富的類型,它們僅受你選用的那種語言的功能集的限制。具體地說,在開發(fā)類型和方法的時候,如果 希望它們對外“可見”,能夠從符合 CLS 的任何一種編程語言中訪問,就必須遵守由 CLS 定義的規(guī)則。注意, 假如代碼只是從定義(這些代碼的)程序集的內(nèi)部訪問,CLS 規(guī)則就不適用了。
到目前為止,除了IL匯編語言支持CLR所有的功能特性之外,其他大多數(shù)面向CLR的語言都只提供了CLR部分的功能。也就是說這些語言的功能都是CLR功能特性的一個子集,但為了實現(xiàn)與其他語言的互操作性,他們的功能都是CLS的一個超集(但不一定是同一個超集)。
想了解更多關(guān)于CLS的信息,請點擊這里。
如果想要寫出遵循CLS的代碼,必須要保證一下幾個部分的代碼遵循CLS。
小提示:在您的私有類的定義中、在公共類上私有方法的定義中以及在局部變量中使用的功能不必遵循 CLS 規(guī)則。 您還可以在實現(xiàn)您的類的代碼中使用任何想要的語言功能并讓它仍是一個符合 CLS 的組件。
注意:交錯數(shù)組(jagged arrays)符合 CLS。 在 .NET Framework 1.0 版中,C# 編譯器錯誤地將其報告為不符合。
可以使用 CLSCompliantAttribute 將成程序集、模塊、類型和成員標(biāo)記為符合CLS或者不符合CLS。 未標(biāo)記為符合 CLS 的程序集將被認(rèn)為是不符合 CLS 的。 如果沒有 CLS 特性應(yīng)用于某個類型,則認(rèn)為該類型與在其中定義該類型的程序集具有相同的 CLS 遵從性。 同樣,如果沒有 CLS 特性應(yīng)用于某個成員,則認(rèn)為該成員與定義該成員的類型具有相同的 CLS 遵從性。 如果程序元素中包含的元素未標(biāo)記為符合 CLS,則不能將此程序元素標(biāo)記為符合 CLS。
以下代碼示例了CLSCompliantAttribute的使用:
using System; // 告訴編譯器要檢查代碼是否符合CLS [assembly: CLSCompliant(true)] namespace CLS_CS { public class CsClass { // 警告: “CLS_CS.CsClass.Abc()”的返回類型不符合 CLS // UInt32不符合CLS。 public UInt32 Abc() { return 0; } // 警告:僅大小寫不同的標(biāo)識符“CLS_CS.CsClass.abc()” // abc和Abc是兩個的方法名稱僅僅是大小寫不同。 public void abc() { } //沒有警告:私有方法不會促發(fā)CLSCompliant規(guī)則 private UInt32 ABC() { return 0; } } }
在編譯這段代碼的時候,由于使用了[assembly: CLSCompliant(true)]特性,編譯器就會檢查代碼是否符合CLS,同時對于不符合CLS的部分給出警告。
事實上,只要滿足一下兩個條件,即使程序集、模塊或者類型的某些部分不符合CLS,這些程序集、模塊或者類型也可是是符合CLS的:
對于第一個條件,只要在上面的代碼中相應(yīng)的地方使用[CLSCompliant(false)],就可以讓編譯器不再產(chǎn)生這些警告,生成的還是一個符合CLS的程序集。
using System; // 告訴編譯器要檢查代碼是否符合CLS [assembly: CLSCompliant(true)] namespace CLS_CS { public class CsClass { // 沒有警告 // UInt32不符合CLS。 [ CLSCompliant(false)] public UInt32 Abc() { return 0; } // 沒有警告 // abc和Abc是兩個的方法名稱僅僅是大小寫不同。 [CLSCompliant(false)] public void abc() { } //沒有警告:私有方法不會促發(fā)CLSCompliant規(guī)則 private UInt32 ABC() { return 0; } } }
但是,這樣一來,其他語言的模塊就不能很方便的訪問這些成員了。在必要情況下,需要使用第二個條件,即為不符合CLS的成員提相應(yīng)的符合CLS的替換成員。
為了方便開發(fā),有些編譯器已經(jīng)為我們做好了類似的工作,即在編譯階段已把某些不符合CLS的功能編譯成了符合CLS的特性。這里以操作符重載為例,前面已經(jīng)說過,有些面向CLR的語言是不支持操作符重載的,因此操作符重載并不是CLS的一部分。那么編譯器是如何處理操作符重載的呢。 以下代碼簡單的示例了操作符“<”和“>”的重載:
using System; // 告訴編譯器要檢查代碼是否符合CLS [assembly: CLSCompliant(true)] namespace CLS_CS { public class Operatorcs { // 重載操作符 public static Boolean operator >(Operatorcs t1, Operatorcs t2) { return true; } // >和 <的重載必須要成對出現(xiàn) public static Boolean operator <(Operatorcs t1, Operatorcs t2) { return true; } } }
將這段代碼編譯成程序集,然后用IL反編譯工具查看生成的IL代碼。這里使用的是ILDasm.exe,當(dāng)然,你也可以使用一些其他的工具,例如.Net Reflector、ILSpy等。
GreaterThan”和“opLessThan”的靜態(tài)方法,而且這兩個方法的返回值和簽名都和源碼中操作符重載的方法一致,由此,可以推測編譯器將操作符重載“翻譯”成了對應(yīng)的靜態(tài)成員。
而事實正是如此,雖然操作符重載不是CLS的一部分,但是所有面向CLR、符合CLS的語言都會支持類型、成員、屬性、字段這些特性。編譯器利用這一點用符合CLS的成員方法代替不符合CLS的操作符重載,巧妙的避開了CLS的規(guī)則校驗,這也是為什么這段代碼雖然也使用了[assembly: CLSCompliant(true)] 但沒有報出“不符合CLS”的警告的原因。
什么是CTS
需要記住的是CLR所有功能的實現(xiàn)都是基于類型的。一個類型將功能提供給一個應(yīng)用程序或者另一個類型來使用。通過類型,用一種編程語言寫的代碼能與用另一種語言寫的代碼溝通。由于類型是CLR的根本,微軟專門為如何定義、使用和管理類型定義了一個正式的規(guī)范-- 通用類型系統(tǒng)(Common Type System),即CTS。
CTS對類型的定義和行為特性給出了規(guī)范,這些特性包括但不僅限于以下幾點:
同時,所有引用類型都必須繼承自System.Object的規(guī)則也是在CTS中定義的。
一般來說,CLS主要提供了一下功能:
CLR是如何工作的
借用維基百科上的一副圖來描述CLR的運行流程:
從源代碼到應(yīng)用程序執(zhí)行CLR主要做了以下工作:
將源代碼編譯成托管模塊
托管模塊是一個標(biāo)準(zhǔn)的 32 位 Microsoft Windows 可移植執(zhí)行體(PE32)文件,或者是一個標(biāo)準(zhǔn)的 64 位 Windows 可移植執(zhí)行體(PE32+)文件,它們都需要 CLR 才能執(zhí)行。一個托管模塊主要包含一下幾部分信息:
PE32貨PE32+頭
這里描述了當(dāng)前托管模塊的基本信息,包括運行的Windows版本、文件類型、生成時間等。對于包含本地 CPU代碼的模塊,這個頭包含了與本地 CPU 代碼有關(guān)的信息。
CLR頭
包含使這個模塊成為一個托管模塊的信息(可由 CLR 和一些實用程序 進(jìn)行解釋)。頭中包含了需要的 CLR 版本,一些 flag,托管模塊入口方 法(Main 方法)的 MethodDef 元數(shù)據(jù) token,以及模塊的元數(shù)據(jù)、資 源、強(qiáng)名稱、一些 flag 以及其他不太重要的數(shù)據(jù)項的位置/大小
元數(shù)據(jù)
每個托管模塊都包含元數(shù)據(jù)表。主要有兩種類型的表:一種類型的表 描述源代碼中定義的類型和成員,另一種類型的表描述源代碼引用的 類型和成員
IL (中間語言)代碼
編譯器編譯源代碼時生成的代碼。在運行時, CLR 將 IL 編譯成本地 CPU 指令
將托管模塊合并成程序集
CLR 實際不和模塊一起工作,而是和程序集一起工作的??梢詮囊韵聝牲c對程序集有一個初步的認(rèn)識:
加載CLR
在這一步,Windows 檢查好 EXE 文件頭,決定是創(chuàng)建 32 位、 64 位還是 WoW64 進(jìn)程之后,會在進(jìn)程的地址空間中 加載 MSCorEE.dll 的 x86,x64 或 IA64 版本。如果是 Windows 的 x86 版本,MSCorEE.dll 的 x86 版本在 C:\Windows\System32 目錄中。如果是 Windows 的 x64 或 IA64 版本,MSCorEE.dll 的 x86 版本在 C:\Windows\SysWow64 目錄中,64 位版本(x64 或者 IA64)則在 C:\Windows\System32 目錄中(為了向后 兼容)。然后,進(jìn)程的主線程調(diào)用 MSCorEE.dll 中定義的一個方法。這個方法初始化 CLR,加載 EXE 程序集, 然后調(diào)用其入口方法(Main)。隨即,托管的應(yīng)用程序?qū)硬⑦\行。
執(zhí)行程序集中的代碼
到目前為止,源代碼已經(jīng)被編譯成二進(jìn)制的IL并且包含在程序集中,而且被CLR加載。但是,直接執(zhí)行運算的CPU來說二進(jìn)制的IL還是太高級了,而且不同的CPU支持的指令集也有所差異。因此,CLR在這里還需要對已經(jīng)編譯好的IL再次編譯,針對CPU版本生成可以直接運行的CPU指令,這個過程是由JIT(Just In Time)編譯器完成的,可以稱作“即時編譯”。
當(dāng)?shù)谝淮螆?zhí)行某個函數(shù)時,MSCorEE.dll 的JITCompiler函數(shù)會從程序集的元數(shù)據(jù)中獲取該方法和方法的IL,并且分配一塊內(nèi)存地址,然后將IL編譯成的本地代碼放入這塊內(nèi)存,然后執(zhí)行內(nèi)存中的本地代碼。
當(dāng)再次執(zhí)行這個函數(shù)的時候,由于內(nèi)存中已經(jīng)存在JIT編譯好的本地代碼,因此不需要再次進(jìn)行JIT過程,可以直接執(zhí)行內(nèi)存中的本地代碼。 可以預(yù)知的結(jié)果是,這種情況下應(yīng)用程序啟動后第一次調(diào)用某個模塊所花費的時間要比以后調(diào)用這個模塊要稍微多一些。
現(xiàn)在,通過本地代碼生成技術(shù),已經(jīng)可以在編譯階段就根據(jù)計算機(jī)的的實際環(huán)境生成本地代碼,這樣以來就可以在運行時節(jié)省JIT編譯的時間,提高程序的啟動效率。這看起來是一個不錯的功能,但是實際上運用的不是很廣泛,主要是有一下限制:
CL有哪些功能
這里借用Jeffrey Richter的一段原話:
At first, I thought that the .NET Framework was an abstraction layer over the Win32 API and COM. As I invested more and more of my time into it, however, I realized that it was much bigger. In a way, it is its own operating system. It has its own memory manager, its own security system, its own file loader, its own error handling mechanism, its own application isolation boundaries (AppDomains), its own threading models, and more.
At first, I thought that the .NET Framework was an abstraction layer over the Win32 API and COM. As I invested more and more of my time
into
it, however, I realized that it was much bigger. In a way, it
is
its own operating system. It has its own memory manager, its own security system, its own file loader, its own error handling mechanism, its own application isolation boundaries (AppDomains), its own threading models, and more.
雖然原文中Jeffrey Richter說的是.Net Framework,但很顯然這些功能都是.Net Framework的核心組件CLR來提供的,正是CLR使.Net Framework并不是Win32 API和COM的一個抽象層,而是有了自己的"操作系統(tǒng)"(Jeffrey Richter的意思應(yīng)該是在一定程度上,虛擬機(jī)也可以認(rèn)為是一個小型的操作系統(tǒng))??偨Y(jié)起來,CLR主要提供了一下功能:
來自: 昵稱10504424 > 《工作》
0條評論
發(fā)表
請遵守用戶 評論公約
[你必須知道的.NET] 第七回:品味類型---從通用類型系統(tǒng)開始
CLR VIA C#之旅(1):品味細(xì)節(jié),CLR的執(zhí)行模型
從菜鳥剛接觸到.net時,菜鳥就知道CLR VIA C#是一本很牛的書,為什么?3)IL(中間語言)代碼:編譯器編譯源代碼后生成的代碼,在運行的...
C#學(xué)習(xí)筆記(一)——軟件構(gòu)建與.NET平臺
2 通用類型系統(tǒng)與公共語言規(guī)范。此外,CTS建立了一套定義明確的核心數(shù)據(jù)類型,以字符串類型為例:String(VB.NET)、string(C#)、Stri...
精彩 .NET 2015
ASP.NET 5 可以在.NET Framework 4.6 或.NET Core 5 上運行,今天,ASP.NET 5 在 Linux 和 Mac 上運行,使用的是 Mono runtime,一旦 .N...
CLR 這些年有啥變化嗎?
CLR內(nèi)部結(jié)構(gòu)。CLR 在整個.Net Framework 程序執(zhí)行過程的模型,C#、VB.Net,C++.Net 代碼通過編譯器生成了MSIL(托管代碼),然后CLR用JIT...
.Net編譯原理簡單介紹
雙擊這個文件,CLR會把其加載到內(nèi)存中,這時要出場的就是及時編譯器JIT. 及時編譯器的作用就是識別IL文件,然后操作CPU去完成相應(yīng)的操作...
全面認(rèn)識.NET框架(一)
CLS還建立了CLS 遵從性要求,可幫助用戶確定托管代碼是否符合CLS以及一個給定的工具對托管代碼(該代碼是使用CLS功能的)開發(fā)的支持程度...
C#與C++,JAVA的比較
C#(讀做 "Csharp")是微軟公司在去年六月發(fā)布的一種新的編程語言,并定于在微軟職業(yè)開發(fā)者論壇(PDC)上登臺亮相.C#是微軟公司研究員AndersHejlsberg的最新成果.C#看起來與Java有著驚人的相似;它...
常用的.NET面試問題 - 1
答:托管代碼是由CLR而不是操作系統(tǒng)執(zhí)行的代碼,編譯器首先將托管代碼編譯為中間語言代碼。另一方面,非托管代碼是在CLR環(huán)境或操作系統(tǒng)...
微信掃碼,在手機(jī)上查看選中內(nèi)容