重學c#系列——c#執行原理(二)
阿新 • • 發佈:2020-07-12
### 前言
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現在開發就比較輕