重學c#系列——c#運行原理(二)

前言

c# 是怎麼運行的呢?是否和java一樣運行在像jvm的虛擬機上呢?其實差不多,但是更廣泛。

c# 運行環境不僅c#可以運行,符合.net framework 開發規範的都可以運行。

c# 程式在.net framework 上運行,而這個.net framework是windows獨有的,所以這就是為什麼以前c#不跨域的原因,現在c#可以運行在.net core 上,而.net core 跨平台還跨語言。

無論.net core還是.net framework都包括名為(公共語言運行時(CLR))的虛執行系統和一組統一的類庫。

正文

什麼是CLR

下面是對CLR的介紹:

CLR 是由 Microsoft 執行的公共語言基礎結構 (CLI) 的商業實現,CLI 是作為執行和開發環境(語言和庫在其中無縫協作)創建依據的國際標準。

這樣解釋似乎不夠通俗,那麼它到底幹了啥呢。

舉幾個例子:

(1)類載入器:管理元數據,載入和在記憶體中布局類;
(2)Micorsoft 中間語言(MSIL)到本地程式碼編譯器:通過即時編譯把Micorsoft 中間語言轉換為本地程式碼;
(3)程式碼管理器:管理和執行程式碼;
(4)垃圾回收器:為NET.Framework下的所有對象提供自動生命期管理,支援多處理器,可擴展;
(5)安全引擎:提供基於證據的安全,基於用戶身份和程式碼來源;
(6)調試器:使開發者能夠調試應用程式和根據程式碼執行;
(7)類型檢查器:不允許不安全的類型轉換和未初始化變數MSIL可被校驗以保證類型安全。

這樣一看這和java 的虛擬機非常像啊,這東西難道就是虛擬機。

下面這種圖,一看就更像了啊:

不管是什麼語言,在.net 平台上開發,然後轉換成MSIL語言(這裡解釋一下為什麼CLR為什麼叫公共語言運行時,因為只要能編譯成MSIL就能在這上面運行),然後通過CLR運行在windows上。

那麼CLR 是否是像JVM一樣的虛擬機呢?

CLR是一個支援多種程式語言及多語言互操作,完整的高級虛擬機。他們做的事情差不多,但是他們的實現原理和運行方式差異巨大。

具體可參考://github.com/dotnet/coreclr/blob/master/Documentation/botr/intro-to-clr.md

既然CLR是一個運行公共語言的虛擬機,運行的還是MSIL語言,那麼這個MSIL語言是怎麼來的呢?這就是微軟貢獻特別大的地方了,微軟向ECMA提供了一份公共語言開發的規範。

下面貼一下概念:

·CLR(公共語言運行庫)是一個CLI的實現,包含了.NET運行引擎和符合CLI的類庫。我們開發的幾乎所有的.NET程式都基於CLR的類庫來實現,並且運行在CLR提供的運行引擎之上。

·CLI(公共語言基礎)是微軟公司向ECMA提交的一份語言和數據格式規範,CLR是目前為止唯一一個公共語言基礎的實現版本。CLI包括了公共類型系統(CTS)、公共中間語言(CIL)、底部文件格式以及元數據格式等

·CTS(公共類型系統)定義了一個能夠在CLR上運行的語言規範。儘管有很多語言本身不符合CTS規範,但是通過加強編譯器,改變語言附加規範等手段,使得許多語言能夠編寫出能在CLR上運行的程式。
一種語言編寫的程式編譯能夠在CLR上運行,並不代表這種語言本身完全符合CTS的規範。例如C++語言,仍然保持了其不符合CTS規範的部分,並且在編譯時把這部分不符合CTS的程式碼編譯成原始程式碼而非中間程式碼。

·CLS(公共語言規範)是CTS的一個子集,它定義了希望編寫在.NET平台上運行的程式的語言所需符合的最小規範。正因為.NET允許由不同語言編寫的程式一起執行,所以才制定出CLS規範,
用以避免不同語言特性產生的錯誤。在.NET Framework中,幾乎所有(但不是所有)的類都是與CLS兼容的。在MSDN文檔說明中,不兼容的類和方法都被特別標記為不兼容,例如System命名空間中的UInt32結構。
UInt32表示32位無符號整數。並不是所有的語言(例如Visual Basic.NET或J#)都支援無符號的數據類型,這種數據類型是與CLS不兼容的。

既然是介紹c#,那麼就看下c# 到CLR的運行過程吧。如下圖:

由上圖可以看到只需要修改下面部分,即可實現將原來windows的那一套搬運到不同的平台上。

現在的.net core就是通過修改這部分來實現跨平台的,真的是大手筆。以前有一個mono(Mono根據C#和CLR的ECMA標準實現了一份Linux下的CLR,比如說,Linux里沒有註冊表的概念,Mono用一個.ini文件來模擬註冊表。),

我嘗試使用過,小型網站用用還是可以的(老項目沒有windows主機可以放一下),效率的確低了一些,只是嘗試部署過一次。

.NET Standard

這東西比較關鍵,是一套規範。

官方文檔這樣介紹道:

NET Standard 是一套正式的 .NET API 規範,有望在所有 .NET 實現中推出。
推出 .NET Standard 的背後動機是要提高 .NET 生態系統中的一致性。
ECMA 335 繼續為 .NET 實現行為建立統一性,儘管 ECMA 335 指定了一小組標準庫,但 .NET Standard 規範包含範圍更廣的 .NET API。

這東西伴隨著.net core 一起誕生。

這東西出現是解決這樣一個問題的。

現在有.net framewore還有.net core,那麼就有一個問題啊,都是用c#在不同平台上開發,他們調用的api是否一致呢?

比如說有個在.net framework 上有個叫做System.IO.FileSystem的api庫,那麼在.net core上文件操作是否也叫這個呢?

所以為了統一就制定了一套規範,叫做標準庫,是.net framework和.net core 都有的,有些是.net core上沒有的,比如D3D只有windows作業系統上有,Linux根本就沒有這個東西,所以不會加入標準庫。

同理用標準庫開發的東西是可以在兩套平台上跑的。

NET Standard 一直在更新,這是歷史原因,那就是當時出來.net core的時候有些api是.net framework 有但是.net core沒有的,這個也不是說是windows都有的api,而是說當時來不及。

NET Standard 2.0 中的新增功能這樣寫道:

.NET Standard 2.0 新增了以下功能:

大幅擴展了 API 集

.NET Standard 版本 1.6 中包含了相對較小的一部分 API。 

不包含的 API 許多都是 .NET Framework 或 Xamarin 中的常用 API。

這樣一來,開發變得更為棘手,因為開發人員必須在開發定目標到多個 .NET 實現的應用和庫時,尋找常用 API 的合適替代項。

為了消除此限制,.NET Standard 2.0 向 Standard 舊版本 .NET Standard 1.6 中的可用 API 補充了 20,000 多個 API。 

隨著時間的推移,.net core現在開發就比較輕鬆了。