扒一扒.net、.net framework、mono和Unity


zhaichao

標簽: .net.net frameworkc#monounity
做Unity項目已經有一年多了,知道Unity用Mono來實現跨平台,但是對於.net .net framework和mono一直只是一知半解。最近在做一個Unity項目需要從外部動態加載場景以及腳本,於是乎對.net framework和mono仔細研究了一發,這里也做一點總結。不過水平有限,如有錯誤求輕噴。
首先看一下github上.net core項目的主頁,大概了解一下.net是干嘛的:
可以看到這個主頁下面有幾個子項目,其中有幾個名字看上去很熟悉,比如coreclr,不就是CLR虛擬機么,corelx,看描述像是提供FCL的,cli,耳熟能詳的通用語言基礎結構,另外還有一個standard項目,里面是關於.net Standard方面的內容,Standard項目中有一個關於Standard version的文檔:
另外在Standard項目的Readme中有如下描述:
所以可以總結一下,.net從一個抽象上來說其實是一個理念,即使得多種語言編寫的程序能夠通過一個通用的runtime運行在不同的操作系統以及硬件平台上。但光有理念不行,還需要實現,我們這里把對於.net里面的某個實現叫做.net platform(比如.net framework就是一個在windows上實現的.net platform,mono則是一個跨平台的.net platform)。一個.net platform想要達成.net的目標,就需要一些組件,比如上圖中CLR通用語言運行時,比如FCL基礎類庫,比如各種語言的編譯器,編譯器編譯出來的東西想要能在CLR中運行,那也需要遵循一定的標准,這就是CLI和CIL,CIL規定了編譯輸出的規則,而CLI規定了編譯器輸入語言的規則,只有符合這種標准的語言才能編譯成CIL語言運行在CLR中。
好了現在有了CIL和CLR,程序員可以用符合CLI的語言比如C#編寫程序了,然后將其編譯成CIL,最后在CLR中運行。但是問題來了,程序員開發程序的時候需要用到一些功能以及數據結構,不可能所有的功能細節都自己實現,不然開發成本也太高了,所以就需要提供一些基礎類庫,方便程序員進行開發,那么需要提供哪些基礎類庫呢?這也需要一個標准,而.Net Standard就是用於這個目的,它規定了某個.net platform需要提供哪些API給開發者。這樣的話加入一個開發者在.net platform A(比如.net framework)上開發了一個項目,然后想遷移到.net platform B(比如Mono)上,那么只要兩個platform實現了同一個.net standard那么源代碼就無需修改可以直接編譯運行。
不過還有一個問題,假如我有一台機器,裝了.net platform A(比如.net framework)和.net platform B(比如Mono),那么我在A上編譯出來的一個.net程序放到B上可以運行么?理論上應該沒問題,畢竟CIL是統一的,雖然一個是A的CLR一個是B的CLR,但是它們都是用來處理CIL程序,就像java代碼編譯出來既可以運行在JVM上也可以運行在delvik上一樣。然而實際上不一定,因為CIL本身也不是一成不變的,它也有自己的版本,看下面這個文檔:
里面的表格詳細說明了.net framework和CLR版本之間的關系,從.net framework 2.0到3.5使用的是CLR 2.0,.net framework 4.0以后使用的是CLR 4.0,中間沒有CLR 3.0版本。這也就意味着CIL語言本身也在發生變化,面向CLR 4.0編譯出來的程序自然是不能運行在CLR 2.0上的。
說那到底什么是.net framework呢?個人理解從抽象角度說.net framework是對.net標准(這個標准具體包括CLI,CIL,.net standard等)在windows平台上的一套實現,具體上說.net framework包含一整套解決方案,包含許多字組件,比如編譯器、CLR、FCL等等,其中每個組件都有自己的版本,比如編譯器有自己的版本用於適應不同版本的語言,比如.net framework 3.5的編譯器只支持到C# 3.0,最新已經到C# 7.0了;每個版本的.net framework提供的FCL也在不斷豐富,比如System.LINQ到.net framework 3.5才有;CLR的版本也會不同,之前已經說過了。因此.net framework的版本其實就是其組件版本的一個集合,高版本的.net framework中的每個子組件都進行了一定的版本更新。
其實正常來說.net framework只是對.net標准的一套實現而已,其他的對於.net標准的實現完全可以將各種不同版本的組件組合起來用,比如我一套.net platform提供了.net framework 4.0的FCL和面向C# 6.0的編譯器,但用的是CLR 2.0的運行時,這並沒有什么問題,只要編譯器和運行時匹配就行了(mono就是這么干的)。但是由於.net是微軟提出來的而且.net framework是微軟開發的,那別的.net platform實現自然就已.net framework為標桿,每個版本的.net framework都提供了一些新的features,支持.net framework x.x就是說這個.net platform實現了x.x版本.net framework的特性,比如下面是mono主頁上的文檔:
  

可以看到上面說的是.net 4.6 4.5,這里表示的其實是.net framework,這個圖片的意思就是最新版本的mono已經實現了.net framework 4.6中支持C# 6的特性,以及此外還可以發現只有.net 3.5和2.0是mono完全實現了其所有特性。准確的說其實是mono實現了.net framework的大部分feature,並且還提供了一些mono自己的class library。Mono和.net framework大致有一個對應關系,如這篇文章所說: http://www.cnblogs.com/zhaoqingqing/archive/2016/08/12/5762867.html
這個表似乎不完全正確,mono 2.0實現了System.LinQ組件,這個組件在.net 3.5中提供,所以mono 2.0對應的應該是.net 2.0/3.5,即兩者之和。不過還是可以當做一個參考。所以說加入一個程序集是用.net framework 3.5構建的,引用了一些dll如system.core以及system.linq,那么要想把其導入mono項目中,就必須保證mono的版本高於2.0,不然會找不到相應的引用。
還有一點需要注意,網上很多講.net版本的時候講.net framework version和CLR version混為一談,有些時候說的.net 2.0指的其實是CLR 2.0。另外有些人把System.Environment.Version誤以為是.ne framework版本,其實不是,msdn上說的很明確,這個值指的是CLR的版本:
另外還有一點值得注意,在vs中構建一個.net framework 3.5的項目時是,引用的System.dll是在系統的.net v2.0目錄下的,也就是說.net framework不是獨立的,而是依賴於.net framework 2.0.不過.net 4.0以后的版本好像就不是這樣了,每次新版本都是獨立的。

最后談一下Unity,Unity為了跨平台使用了Mono,其使用的Mono版本可以通過代碼或者命令行方式獲得,unity forum上已經有牛人說明了:
我自己的測試結果是mono 2.0
查了一下mono官網,mono 2.0是08年的老古董(Unity居然還在用,貌似是版權問題,沒有深究),而用vs打開一下Unity中的腳本,查看一下項目構建文件.csproj:
可以看到Unity用的是.net 3.5,所以難道Unity的腳本是用.net framework 3.5構建的?顯然不是。
我們知道vs有一個東西叫VSTU,它最大的作用就是可以用vs的斷點調試功能調試Unity Editor。Unity中的腳本在vs中打開的時候會構建一個VSTU項目。VSTU項目雖然跟普通VS項目看上去很像,但其實VSTU項目本質上並不是真正的vs項目,如果你右鍵項目->屬性是沒有反應的(VSTU 2.1以前有反應,之后就禁用了),而且右鍵項目中的引用也不會有添加引用選項,其實VSTU是把vs當做了一個功能強大的編輯器。
但VSTU不只是利用了VS進行語法檢查這么簡單,它的另一個作用就是斷點調試。在沒有斷點調試的情況下,Unity使用自己的編譯器進行編譯,生成Assembly-CSharp.dll(在/Library/目錄中),點擊Play按鈕的時候用的是這個dll,而用VS進行斷點調試的時候則會用VS的編譯器編譯出Assembly-CSharp.dll以及pdb文件,在\Temp\UnityVS_obj\Debug\目錄中,此時點擊Play用的就是這個dll。當然build出exe的時候用的還是自己的編譯器。
VSTU對項目進行了限制,不能直接在VS中添加新的dll,但可以拷貝到Unity項目的Asset目錄下,這樣Unity會重新構建VSTU項目,把拷進去的dll顯示在引用列表里面。
VSTU構建的項目是基於.net framework 3.5的。因為Unity用的是mono 2.0啊,mono 2.0實現的feature包括.net framework 2.0和3.5,而UnityEngine.dll引用了System.Core.dll,而這個dll在.net framework 3.5才有,如果是是基於.net framework 2.0構建,那么第一有些mono 2.0支持的feature在vs里面就會找不到,另外也無法斷點調試,因為編譯通不過。
其實也可以在Unity的安裝目錄中尋找一些端倪,在windows下為:
C:\Program Files\Unity\Editor\Data\Mono\lib\mono\2.0
這個目錄2.0目測就是mono的版本,目錄中有很多dll,比如System.*.dll,這說明unity自帶了mono項目,提供了mono 2.0中實現的基礎類庫。雖然Unity的腳本可以在像VS以及MonoDeveloper中打開,但是在build的時候用的還是Unity自帶的Mono中的編譯器,而Mono 2.0僅支持到C# 3.0,所以有些最新的語法在Unity里面是無法編譯通過的(Unity 5.3.5 p8提供了一個新的編譯器mono 4.4用於測試,但是似乎沒有下文了)。
總結一下就是,Unity使用的是mono 2.0,支持C# 3.0,提供與.net framework 3.5/2.0 API兼容的類庫(mono 2.0實現了.net framework 2.0 + 3.5的feature,但是沒有實現.net framework 3.0的WPF的feature,所以官網的說法是 .Net 2.0/3.5 framework profile),使用了與CLR 2.0兼容的mono runtime,因此用vs構建Unity的dll需要.net framework 3.5以下,不然runtime不兼容;如果要用到UnityEngine等Unity的功能必須用.net framework 3.5這個版本,不然vs項目找不到System.Core.dll,無法通過編譯,如果只是一些工具類,不需要引用UnityEngine.dll,那么用.net framework 2.0構建是可以的。vs只是一個第三方構建工具,想要構建出Unity能用的dll就不能使用Unity(Mono 2.0)不支持的feature。

最后有一點之前一直在困擾我,但今天稍微有點想通了,就是Unity的Player Setting里面有個API compability Level:
這個只有兩個選項:.Net 2.0和.Net 2.0 Subnet,這個說實話讓人很不解,從字面上講是指API兼容,那兼容到.net 2.0難道是指兼容.net framework 2.0的FCL API?但Unity可以用到.net framework 3.5的一些庫啊。網上找了一通以后發現了如下網址:
以及這個Question:
其中有一句話很關鍵:
The 2.0 there is likely a good reflection of what you have at least
所以梳理一下就是.Net 2.0和.Net 2.0 Subnet是指編寫的C#代碼能夠引用的函數集合的不同,如果選擇了subset那么dll就不會被導入到項目中來。比如同一個項目用.Net 2.0和.Net 2.0 Subnet構建出來的目錄如下,可以很明顯看到兩者的差別。
   

當新建一個Unity項目時,只會有一些核心的dll會被導入到項目中,其他的dll需要從外部拷貝到項目的Asset文件夾下,VSTU項目中是不能直接添加引用的,個人感覺VSTU對項目的限制有點多,像是把開發者當成傻子,因為你在用Unity那么這些功能就給你禁用掉,不過目測可以通過修改.sln或者.csproj文件來實現一些特殊需要。那.net framework 3.5呢?其實Unity支持的是.net framework 2.0 + 3.5,跳過了3.0,因為3.0是WPF的,Unity不需要,.net 2.0指的是你至少可以用哪些feature。
Unity最近因為加入了.Net基金會,出了幾個用最新mono的測試版:
Unity 5.5.0 b4里面API compability Level增加了一個4.6選項,其實是把原來的mono 2.0換成mono 4.6進行測試,mono 4.6支持C# 6.0,並且開發者可以使用.net 4.6的API寫程序,然而也不知道什么時候能有穩定版。而且mono都快要被淘汰了,以后目測都是IL2CPP了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM