1. 程式人生 > >重學c#系列——c#執行原理(二)

重學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 的虛擬機器非常像啊,這東西難道就是虛擬機器。 下面這種圖,一看就更像了啊: ![](https://img2020.cnblogs.com/blog/1289794/202007/1289794-20200712112129562-1947025120.png) 不管是什麼語言,在.net 平臺上開發,然後轉換成MSIL語言(這裡解釋一下為什麼CLR為什麼叫公共語言執行時,因為只要能編譯成MSIL就能在這上面執行),然後通過CLR執行在windows上。 那麼CLR 是否是像JVM一樣的虛擬機器呢? CLR是一個支援多種程式語言及多語言互操作,完整的高階虛擬機器。他們做的事情差不多,但是他們的實現原理和執行方式差異巨大。 具體可參考:https://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的執行過程吧。如下圖: ![](https://img2020.cnblogs.com/blog/1289794/202007/1289794-20200712122912001-1871668957.png) 由上圖可以看到只需要修改下面部分,即可實現將原來windows的那一套搬運到不同的平臺上。 ![](https://img2020.cnblogs.com/blog/1289794/202007/1289794-20200712124040764-1928921510.png) 現在的.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 一起誕生。 ![](https://img2020.cnblogs.com/blog/1289794/202007/1289794-20200712130103330-985352589.png) 這東西出現是解決這樣一個問題的。 現在有.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現在開發就比較輕