前段時間,被問了這樣一個問題:.NET 應用程序是怎么運行的?
當時大概愣了好久,好像也沒說出個所以然,得到的回復是:這是 .NET 程序員最基本的。。。呵呵!
微軟開源,其實不只是對 .NET 本身有利,從另一方面講,對于 .NET 程序員來說,因為開源,你可以想了解到你想要的任何事。在之前的歲月,你可以“平凡”做一個默默無聞的 C# 代碼撰寫者,可以不用考慮任何事,使用宇宙最強大的 IDE - Visual Studio 編寫代碼后,發布到 IIS 即可,就是這么簡單,甚至你不需要知道 IIS 是怎么運行的,代碼是怎么托管的等等,你只需要寫好你的 C# 代碼即可,因為其余的一切工作,微軟已經幫你考慮并完成了。這樣雖然簡單并且高效,但對于 .NET 程序員來說,這就像“井底之蛙”一樣,你看不到外面的世界,你也沒有任何動力去跳出這個“深井”,而只是“舒適”的觀望著外面你所認為的“狹隘世界”。但因為開源、跨平臺,這些平靜的日子都將被打破了,微軟開源出來的一個個項目、發表的一篇篇文章,怎么越來越看不懂了?最后才發現,現在的微軟已經不是原來我們熟悉的那個微軟了,.NET 亦是如此。
我大概花了幾天的時間,去真正閱讀 .NET 開源的一些文章,雖然英文很爛,但我都堅持讀了下來,閱讀過程中,越來越被 .NET 的魅力所吸引,并時不時的被一些“特殊表達“所逗笑,但這都只是在閱讀的過程中,讀完、思考完,回到上面的那個問題,我還是不能很好的去表述、回答它,這時候我就意識到:腦子不好使,需要博客記錄,這篇博文可以當做一篇閱讀筆記來看(再一次的閱讀)。
在很久很久之前,如果提到 .NET 跨平臺,你首先想到的應該是 Mono,那 Mono 到底是什么?它為什么可以跨平臺?在 .NET 開源之前,我對這些是一無所知,理解微軟這次 .NET 跨平臺,需要首先了解 Mono,了解 Mono,首先你需要仔細閱讀下這篇文章:http://www.wikipedia.org/wiki/Mono。
Mono 是一個由 Xamarin 公司(先前是 Novell,最早為 Ximian)所主持的自由開放源代碼項目。該項目的目標是創建一系列符合 ECMA 標準(Ecma-334 和 Ecma-335)的 .NET 工具,包括 C# 編譯器和通用語言架構。與微軟的 .NET Framework(共通語言運行平臺)不同,Mono 項目不僅可以運行于 Windows 系統上,還可以運行于 linux,FreeBSD,Unix,OS X 和 Solaris,甚至一些游戲平臺,例如:Playstation 3,Wii 或 XBox 360。
重要的兩點:
再來看兩個概念:
公共語言基礎(Common Language Infrastructure,CLI)是一套標準(ECMA335),公共語言運行時(Common Language Runtime)即 CLR 是 CLI 標準的實現,Mono 是實現者之一。該運行時用于執行已編譯的 .NET 應用程序。公共語言基礎已被 ECMA 定義為標準 ECMA-335。要運行一個 .NET 應用程序,你必須使用相應的參數調用運行時。通用語言基礎架構定義了構成 .NET Framework 基礎結構的可執行碼以及代碼的運行時環境的規范,它定義了一個語言無關的跨體系結構的運行環境,這使得開發者可以用規范內定義的各種高級語言來開發軟件,并且無需修正即可將軟件運行在不同的計算機體系結構上。
公共語言規范(Common Language Specification,CLS)定義了提供給公共語言基礎的接口,例如對于枚舉類型的隱含表示類型的協定。Mono 的編譯器負責生成符合公共語言規范的映射代碼,即公共中間語言(Common Intermediate Language,CIL)。Mono 的運行時將運行這類代碼。ECMA 標準先前還定義了一個符合公共語言規范的程序庫作為應用框架。
對于上面一大堆的協議或概念,理解起來是需要花點時間,首先 Mono 的各個部分都是基于各種開源協議,也就是說它是一個徹徹底底的開源項目,再來大致理一下協議及其實現:
可以用來回答博文一開始那個問題的一張圖:
開發人員使用高級編程語言撰寫程序,接下來編譯器將代碼編譯成微軟的中間語言(MSIL),運行的時候 CLR 會將 MSIL 代碼轉換為操作系統的原生代碼(Native code),CLR 內置有實時編譯器(中間代碼轉化為原生代碼的編譯器)。
是不是還是有點暈?其實說簡單也簡單,拋開應用程序和編譯器,.NET 的運行機制組成,其實就只有 CIL 和 CLR,CIL 是編譯器生成的中間語言,CLR 的作用就是將它再編譯成原始機器代碼。你可能還有一個疑問,我們常說的 .NET Framework 到底是什么?它在 .NET 運行機制中到底扮演什么角色?在上面演示圖中,其實 Source Code 并不包含 .NET Framework,Source Code 指的是你應用程序的源代碼,在上面有提到,.NET Framework 是以 CLR 為基礎的開發庫,你可以把它看作是編譯好的 CIL,它并沒有通過編譯器的再次編譯過程,而是直接通過 CLR 中的編譯器編譯為原始機器代碼。
簡要總結:
好了,我們再猜想一下,如果把 .NET 運行機制的各個組件進行分開重組,除去 .NET Framework 是微軟提供的,其余的組件,比如 C# 編譯器、CIL、CLR 等,都是 Mono 基于各種協議進行實現的組件,那如果你的應用程序代碼引用了 .NET Framework(微軟實現),很顯然,這個應用程序是無法運行的,因為實現的 CLR 并不是微軟的 CLR,所以針對 .NET Framework 來說,因為它的不開源,所以 Mono 需要另行實現基于自己 CLR 的基礎類庫,但這是一個龐大而復雜的工程,所以現在的 Mono 基礎類庫并不是很完整,很多東西和微軟的 .NET Framework 并不能很好的兼容,所以你如果使用 Visual Studio 開發的項目,想遷移到 Mono Develop 下,是非常復雜的,當然,如果你沒有使用任何的 .NET Framework,是非常簡單的,但現實是,敲個最簡單的“Hello World”輸出代碼,都得引用 mscorlib.dll 程序集(System.Console)。
上面描述那么多,我想表達什么呢?其實我們現在在 Windows 平臺下開發的 .NET 應用程序,是深深依賴于 .NET Framework(深深的那種),你的應用程序代碼基本上都是在它之上完成的,而 .NET Framework 又是深深依賴于 Windows 平臺下的 CLR(也是深深的那種),在這種情況下,根本就無法使你的應用程序跨平臺,因為微軟緊緊的抱住 Windows 平臺,妄想 Windows 可以實現“大一統”,但現實是很殘酷的,這次的 .NET 開源、跨平臺,其實也是微軟的無奈之舉。但就是在這種背景下,Mono 出現了,并且在微軟的各種“排擠”下堅持了下來,這是非常不容易的,其實實現 .NET 跨平臺的三個關鍵是:編譯器、CLR 和基礎類庫,而 Mono 實質上就是把他們三個進行跨平臺實現了,一個很小團隊完成了一個巨頭需要完成的工作,而且還是在這個巨頭的“排擠”下,其實這就是開源和社區的力量。
Mono 就說到這,有些疑問先放下,后面再進行講解,下面我們來說一下 .NET Core 的相關內容。
需要認真閱讀的一篇文章:.NET Core is Open Source
這是 .NET 開源的一篇官方說明文章,內容很多(包括評論),如果你真正花時間去讀的話,這篇文章的信息量是非常大的,下面是我搜刮的一些片段。
.NET Core 開源地址:https://github.com/dotnet/corefx。
.NET Core 包含:
編譯器、asp.net:
答:.NET Core is a modular development stack that is the foundation of all future .NET platforms It’s already used by ASP.NET 5 and .NET Native.
關鍵詞:Modular(模塊化),現在的 .NET Core 只是增加了 .NET Core Framework 的一些代碼,.NET Runtime 并未添加任何代碼,這個需要時間,既然代碼都未添加完善,那為什么 ASP.NET 5 and .NET Native 現在可以跨平臺了?因為他們沒有使用 .NET Core,而是使用獨立的 Runtime-KRuntime,現在已更名為 XRE。
比較“官方”的回答:
其實翻譯過來就是“形勢所逼”,但事實真是如此嗎?其實也不盡然,看這一段敘述就明白一些了:
The challenge is that the Windows implementation has one code base while Mono has a completely separate code base. The Mono community was essentially forced to re-implement .NET because no open source implementation was available. Sure, the source code was available since Rotor but we didn’t use an OSI apPRoved open source license, which made Rotor a non-starter. Customers have reported various mismatches, which are hard to fix because neither side can look at the code of the other side. This also results in a lot of duplicated work in areas that aren’t actually platform specific. A recent example is immutable collections.
這段敘述是很有意思的,因為 .NET 的不開源,Mono 社區重寫了跨平臺的 .NET,又因為 Rotor 沒有基于任何 OSI 開源協議實現,所以導致 Mono 的實現充滿了困難,這些都是微軟親自承認的,想想在以前,微軟會說這些嗎?相反它會高傲的抬起它的頭,其實從這一方面就可以看出,Mono 社區這么多年是多么的不容易,微軟這次的改變也是多么的不容易。為了加深你的印象,微軟列舉了一個最新例子:immutable collections,Mono 團隊是這樣寫的說明:Unfortunately Microsoft didn't release their implementation under a license useable in mono I needed to reimplement the interfaces.,其實你可以看出一種無奈,Immutable Collections 是 .NET Framework 的基礎核心類庫之一,這還是之一,當然還有很多的實現,試想一下,如果 .NET 早就開放 .NET Framework 的源代碼,即使微軟沒有對它進行跨平臺,也會減少 Mono 團隊的開發難度,以及盡量減少與 Windows 平臺實現應用程序的兼容問題,當然這都是后話。
Build and leverage a stronger ecosystem.
關于這部分內容的解讀,微軟主要說了兩點:Nuget 和 Interact,關于 Nuget,dudu 之前好像吐槽了好多次,但是微軟說了,我們花了兩年的時間去做這個東西,并得到了很好的反饋,但好像得到的反饋沒有來自國內,使用 Nuget 的用意,其實就是之前說到的 Modular(模塊化、組件化),這樣的好處就是很好的擴展和維護,Interact 可以理解為開源帶來的交互和進步,可以讓開發者參與,并且反饋問題,利用社區的力量,讓 .NET 更加完善。很有意思的是,在最后作者舉了一個生活的例子:我認為這就像駕駛一輛汽車,方向盤小的調整比大的調整,更加有效果,而且也更加安全,這個小的調整可以看作是來自社區的那一份份“微小”的力量,大的調整,當然是微軟自己單獨搞,想想就知道哪個比較靠譜點。
這部分也是非常有意思的,首先,微軟做了一個調查,發現大部分的 .NET 社區都活躍在 GitHub 上,Don’t believe it?(看到這,我大笑了三聲),不相信的話,微軟給你舉了一個真實的例子,nuproj(作者的一個個人項目),在 CodePlex 上放了兩年,僅僅得到了一個 Pull 請求(想想也挺傷心的),然后把它移到 GitHub 上,僅僅五天后,就收到了三個 Pull 請求和兩個提交,三個月的時間,總共收到了 16 個 Pull 請求和一些很有價值的提交。
作者的感受:one of the first ones was around adding unit testing, how awesome is that? 看來他是非常的激動!
需要注意的是,CodePlex 是微軟構建的 Open Source 網站,它的競爭對手就是 GitHub,而微軟卻如此諷刺自己的“孩子”,并且放棄了它,選擇了別人家的孩子,并把自己的“財產”傳給它,這是需要多么大的勇氣啊,雖然是迫不得已,但讓一個巨頭這樣低頭也是一件很難得的事(此處應該有掌聲)。
這部分主要是講微軟如何做開源開發,提到了他們之前做的一個開源項目-Managed Extensibility Framework (MEF),他們認為這是失敗的,原因很簡單,就是缺少社區的參與,剛才打開這個項目看了
新聞熱點
疑難解答