[點晴永久免費OA].NET科普:.NET簡史、.NET Standard以及C#和.NET Framework之間的關系
當前位置:點晴教程→點晴OA辦公管理信息系統
→『 經驗分享&問題答疑 』
最近在不少自媒體上看到有關.NET與C#的資訊與評價,感覺大家對.NET與C#還是不太了解,尤其是對2016年6月發布的跨平臺.NET Core 1.0,更是知之甚少。在考慮一番之后,還是決定寫點東西總結一下,也回顧一下.NET的發展歷史。 首先,你沒看錯,.NET是跨平臺的,可以在Windows、Linux和MacOS以及它們的各個發行版上運行,不僅如此,從2022年4月28日開始,.NET開源社區正式支持國產龍芯芯片龍架構(LoongArch),這使得.NET在國家信創這一領域又邁出了一大步。咦?.NET跨平臺這事情我知道呀,為何要特別提起呢?因為真的有很多人不知道,而且不乏各種短視頻平臺里出現的各種技術專家和技術大咖,紛紛表示.NET只能在Windows上運行,跨平臺困難,落地和部署困難。 其次,.NET的成功案例有很多,大家都知道,.NET和C#會用在游戲開發、工控領域、老系統維護等項目和場景中,卻并不了解其實下面這些也都是.NET的成功案例,或者有著.NET的影子:
在上面的列表中,有些可能你還不認識,剩下的認識的大部分都是微軟自己的產品,你會說.NET只有微軟自己用,但不管是誰用,這些站點和應用都是超大規模級別的,說明使用.NET來構建超大規模級別的大型應用是完全沒有問題的:容器化、云原生、微服務、Serverless,.NET都可以勝任;AI時代,ML.NET、Semantic Kernel、LLamaSharp、Cognitive Services等等.NET原生框架和開發SDK,在微軟Azure OpenAI Services的加持下,為.NET在AI領域發力提供了更多的機會。 此外,.NET是開源的,.NET的各個部分通過不同的Repository維護在Github上,這些倉儲基本上都是以MIT和Apache 2的許可協議進行開源,由微軟員工作為主要貢獻者,因此,在開源的同時,又保證了倉儲的持續更新維護和提交代碼的質量。不僅如此,.NET Foundation還收納了不少知名開源項目,這對完善整個.NET生態起到了非常積極的作用。 那這里的.NET是指.NET Framework嗎?算是,但也不完全是。之前為大家熟知的那個只能在Windows下運行的版本,稱為.NET Framework,自2016年開始,微軟發布跨平臺版本的.NET框架時,它作為經典.NET Framework的跨平臺版本,被稱之為.NET Core,.NET Core延續到3.1版之后,被改名為.NET 5,然后就是后來的6、7、8、9等各個版本。對于這部分內容,我后面會介紹,但我想在介紹更多詳細信息之前,先簡單地回顧一下.NET的歷史。 .NET極簡史:從Visual J++開始大家都知道,剛剛退休的Java之父詹姆斯·高斯林曾經在1991年就開始參與Java語言的構建,然后Sun Microsystems公司于1996年發布了Java 1.0版本,但很少有人知道,微軟在同年10月份發布了自己的Java語言:Visual J++。Visual J++開發的程序基于微軟自研的MSJVM運行,雖然J++遵循Java語言規范,但微軟并沒有選擇完全根據Sun公司的Java規范來設計自己的JVM,于是,MSJVM實際上并不完全支持Sun Java的所有能力,包括Java RMI和JNI。而另一方面,微軟還在Visual J++中加入了一些自己的設計,比如通過回調函數和委托來實現事件處理,這就使得Visual J++變得更像另一種新的編程語言。不僅如此,Visual J++在訪問系統資源方面,也不遵循Sun Java SDK規范,而是通過自己定義的J/Direct接口來讓代碼直接訪問操作系統層面的API,于是,Visual J++在某些方面性能要大大優于Sun Java(很是懷疑這個J/Direct就是后來的P/Invoke)。從技術角度,使用了這些特殊功能的J++應用程序其實無法在Sun Java JVM上運行,不過當時也有不少開源項目,比如Kaffe項目,它們可以使J++應用程序無需移植即可直接在這些開源的JVM上運行。但這些開源項目也最終沒有被廣泛應用。 一開始的時候,Sun公司愿意在Java語言上與微軟合作,而由于Visual J++里的各種騷功能和騷設計打破了Sun Java規范,以至于MSJVM未能通過Sun公司的合規性測試,于是,在Sun公司的起訴下,微軟逐漸停止了Visual J++的研發。不過,在這個過程中,微軟積累了豐富的技術和經驗,這些技術和經驗逐漸演化成后來的.NET平臺和Visual J#(一種可以運行在.NET Framework上的Java編程語言,注意:是編程語言,就是用Java的語法寫.NET Framework的應用程序)。Visual J#是Visual J++的續作,目的是能夠讓原來的Visual J++開發人員可以平滑地遷移到.NET平臺上。 之后就是2002年4月15日發布的.NET Framework 1.0和Visual Studio.NET 2002(注意是Visual Studio.NET,不是Visual Studio,從Visual Studio 2005開始,名字里去掉了.NET字樣),它可以安裝并運行在Windows NT 4.0 SP6、Windows 98、Windows 98 SE、Windows ME、Windows 2000和Windows XP系統上。當年我正好讀大三,記得數據庫這門課的課程設計,就是用Visual Studio.NET 2002做的。由于操作系統可以是32或者64位的,屬于不同的CPU架構,因此,從這個層面也可以說.NET是跨平臺的:在Windows操作系統下跨平臺。說起跨平臺,雖然一開始由于市場策略、技術實現、開源生態等等因素,微軟最終選擇讓.NET只在Windows下運行,但同時也力求將各種設計通過ISO和ECMA進行標準化,這為后續社區版跨平臺.NET Framework:Mono Project、Xamarin以及.NET Core的出現,打下了堅實的基礎。 值得一提的是,由于CLI標準化的存在,使得任何編程語言,只要符合相關規范,都可以在.NET上運行(這里我就不區分跨平臺.NET還是經典.NET Framework了,單說編程語言這部分內容,兩者原理是一樣的),于是,你可能會看到有人使用以下語言來開發.NET應用程序:
從2002年4月15日到2022年8月9日這20年時間,.NET Framework經歷了大大小小17個版本,功能也在不斷的增強,在2016年隨著.NET Standard的引入,從.NET Framework 4.5開始,不同版本的.NET Framework也被歸屬到對應版本的.NET Standard之下,而發布于2019年4月18日的.NET Framework 4.8,也成為了經典.NET Framework的最后一個版本(雖然2022年8月9日發布了.NET Framework 4.8.1,但并不是一個主版本)。 后續版本的.NET被稱為.NET 5,從版本號上可以看到,.NET 5可以看成是.NET Framework 4.8的延續,它去掉了“Framework”字樣,以示與之前經典.NET Framework的區別,.NET 5及后續版本都是跨平臺的,現在回看這段歷史可以發現,之前的.NET Core 1.0到3.1其實都是.NET跨平臺歷程的中間版本,這些版本存在的價值,就是讓.NET開發人員和用.NET Framework開發的項目可以通過這些.NET Core的版本,能夠無縫地、逐步地過渡到跨平臺的、現代化的.NET上。不得不佩服微軟在.NET跨平臺這方面無論在市場戰略上,還是技術戰術上,都表現得非常出色。 .NET歷史就介紹這么點,了解這些基本也就夠了,接下來我會逐步從技術角度,來介紹一些與.NET相關的新概念。 .NET跨平臺與.NET Standard可以這樣理解:.NET Standard是.NET跨平臺的基礎。.NET Standard其實就是一套.NET下的API規范,它的第一個版本與2016年的.NET Core 1.0同時發布,每一個版本的.NET Standard都規定了實現這一版本規范的不同的.NET實現應該包含哪些API。更具體些:為了跨Linux、MacOS、Windows、iOS、Android等多個平臺,.NET會針對這些平臺提供不同的實現,這些實現包括:.NET Core、.NET Framework、Xamarin套件(iOS、Mac和Andriod)、用于游戲開發的Unity下的.NET等等,如果這些實現能夠遵循某個版本的API標準,那么,基于這個版本的API標準所開發的應用程序,就可以運行于這些不同平臺上,而這套API標準就是.NET Standard。另一方面,如果希望開發出來的類庫和組件能夠被不同平臺的應用程序使用,那么,只需要指定這個類庫和組件所基于的.NET Standard版本即可。 然而,最開始的.NET Framework并不能跨平臺,微軟為了逐步實現.NET跨平臺這個目標,先后發布了從1.0到2.1一共9個版本的.NET Standard,每個.NET Standard版本下,都增加一部分.NET API的支持,比如,.NET Standard 1.0僅支持37118個API中的7949個,.NET Standard 2.0支持37118個API中的32638個,而最新的.NET Standard 2.1則支持所有37118個API。因此,在不同版本的.NET Standard下,就會有對應版本的.NET實現對其進行支持。比如對于.NET Standard 2.0,經典的.NET Framework需要4.6.1及以上的版本才支持.NET Standard 2.0,因為這些版本實現了.NET Standard 2.0中所定義的那32638個API。于是,使用.NET Standard 2.0開發的類庫,就可以被.NET Framework 4.6.1所引用。 演練:在不同的.NET項目中使用.NET Standard 2.0類庫在Visual Studio 2022中,新建一個.NET Standard 2.0的Class Library: 然后加入一個類: 再新建一個經典.NET Framework 4.6.1的Console Application: 然后直接引用前面的 當然,這個 打開這個ClassLibraryNetStandard20項目的輸出目錄,可以看到,編譯出來的程序集被放在了 但是,如果我們新建一個.NET Standard 2.1的Class Library,則無法被.NET Framework 4.6.1的項目引用,此時會報錯: 因為.NET Framework 4.6.1沒有實現.NET Standard 2.1,換句話說,.NET Standard 2.1中的有些API在.NET Framework 4.6.1中并沒有實現,那么基于.NET Standard 2.1開發出來的類庫自然也不能被.NET Framework 4.6.1的項目所引用。經典.NET Framework的最后一個版本4.8.1僅實現了.NET Standard 2.0,因此,如果你打算開發一個既可以被經典.NET Framework項目使用,又可以被跨平臺.NET(曾經的.NET Core,現在的.NET 5+)項目使用的話,你需要將你的類庫定向(targeting)到.NET Standard 2.0,或者使用多目標框架(Multi-targeting)。 在【這個頁面】中,有一張表,展示了.NET Standard各個版本與不同的.NET實現的版本之間的對應關系,可以通過下拉框來選擇不同的.NET Standard版本來查看不同的.NET實現的哪些版本與之對應。理論如此,但是在真正實踐的過程中,有些具體的問題是需要特殊處理的。比如:.NET Framework 4.7是支持.NET Standard 2.0的,但是,.NET Framework 4.7發布于2017年4月,而.NET Standard 2.0則晚于.NET Framework 4.7發布(2017年8月),那么如何讓一個已經發布的.NET Framework版本支持新的.NET Standard呢?解決方案就是使用NuGet Package,將.NET Framework中未實現的.NET Standard API以NuGet Package的形式引入,從而彌補這個差異。因此你會發現,對于.NET Framework 4.7.1及其以前版本的.NET項目,如果需要引用一個由.NET Standard 2.0實現的類庫的話,就需要額外引用
在編譯出來的結果上也存在差異,下面左圖是一個.NET Framework 4.7的項目引用了一個.NET Standard 2.0的項目后的編譯輸出,右圖是.NET Framework 4.8.1的項目引用了.NET Standard 2.0項目后的編譯輸出,可以看到,4.7的項目編譯后,會在編譯路徑下生成一堆System DLL,外加一個 多目標框架(Multi-targeting)盡管.NET Standard提供了不同.NET實現(.NET Framework、.NET Core和Xamarin等)之間統一的API規范,但在有些場景下,仍然希望能夠充分利用不同平臺的特性和性能優化,或者需要支持特定平臺的功能,此時僅將項目定向到.NET Standard已經不能滿足需求。對于這種場景,.NET允許開發面向多目標框架的類庫,一方面可以通過條件編譯指令來使用特定平臺的API,另一方面也可以為類庫的調用方提供不同平臺的支持。 比如,在C#項目文件(.csproj文件)中,使用下面的方式,讓類庫同時支持.NET Standard 2.1項目和.NET Framework 4.8的項目:
注意上面的TargetFrameworks標記,在這個XML標記下,列出了該類庫所支持的.NET Standard/.NET Framework的版本,它在編譯之后,會產生兩個輸出文件夾,其中包含了支持不同版本.NET的程序集: 另一個需要注意的地方是,在上面的csproj文件定義中,指定了所使用的C#版本為8.0,這是因為“可空引用類型”(Nullable Reference Types)是在C# 8.0中引入的,而如果將代碼同時定向到.NET Framework 4.8,那么就無法支持可空引用類型,因為.NET Framework 4.8所支持的最高的C#版本為C# 7.3。有關.NET與C#版本之間的關系,后文我會介紹。 一個使用“多目標框架”的非常著名的開源框架就是log4net。log4net是一個古老的.NET下的日志輸出工具,它一開始是log4j的.NET移植版本,所以,老版本的log4net使用了很多經典.NET Framework特有的API,比如System.Configuration命名空間下的基于XML的框架配置代碼。隨著.NET Core和跨平臺.NET的發布,log4net也逐步提供了對.NET Standard 1.3和.NET Standard 2.0的支持,所以,現在的.NET 5/6/7/8項目都可以直接引用log4net用作日志輸出。在log4net的官方代碼庫中,可以學習到它是如何實現多目標框架的。 事實上從.NET 5開始,.NET真正實現了跨平臺,.NET Standard也基本完成了它的使命,但.NET Standard并不會退出歷史舞臺,微軟會繼續對其進行維護。 至此,與.NET跨平臺和.NET Standard相關的內容就差不多介紹完了,當然還有部分細節和一些歷史遺留問題的處理方式相關內容(比如Portable Class Library,PCLs),這里就不再贅述了,否則篇幅太長,hold不住啊。接下來我們聊聊C#和.NET Framework之間的關系吧。 C#語言特性與.NET Framework如果你是C#語言的初學者,那么你一定會產生一個疑問: 由此可以得出一個結論:C#的語言特性是需要.NET Framework(或者.NET)支持的(有些高級的語言特性甚至需要不同版本的.NET CLR支持),但兩者的版本之間也不一定需要有嚴格的對應關系。C#語言特性本質上是通過C#編譯器實現的,只要編譯輸出的MSIL代碼能夠在.NET Framework(或者.NET)上運行起來,那么這些語言特性就可以被該版本的.NET Framework所支持。下面請看一個具體的案例。 演練:在.NET Framework 4.6.1的項目中使用C# 9.0的新特性現在我們嘗試在一個.NET Framework 4.6.1(發布于2015年11月)的項目中,使用C# 9.0(發布于2020年11月)的新特性。首先新建一個.NET Framework 4.6.1的Console Application: 然后,修改csproj文件,將C#語言版本升級到C# 9.0: 然后,使用C# 9.0中“關系型模式匹配”新特性編寫一段代碼: 然后直接運行,可以看到,程序是可以正常編譯執行的: 那么,是不是所有的C# 9.0的新特性,都可以在.NET Framework 4.6.1中使用呢?答案是否定的,就要看C# 9.0的編譯器是否可以生成能夠被該版本.NET Framework所支持的代碼,或者說,C#編譯器所生成的代碼中依賴的那些類型,是否在該版本的.NET Framework下支持。舉個例子,同樣是C# 9.0的新特性,僅限Init的資源庫新特性則無法直接在一個.NET Framework 4.6.1的項目中使用,編譯器提示: 原因是,C# 9.0編譯器在編譯帶有這個新語法特性的代碼時,需要檢查.NET下是否包含 請注意:經典.NET Framework最高支持到C# 7.3,C# 8.0是專門面向.NET Core的第一個主要C#版本,它的一些新功能依賴于新的Core CLR的相關功能。【這篇官方文檔】詳細列舉了C#語言的發展歷史以及各個版本的新功能,下面這張表格列舉了不同.NET版本下,創建新項目時所使用的默認的C#語言版本(參考官方文檔): 轉自https://www.cnblogs.com/daxnet/p/18299758 作者dax.net 該文章在 2024/7/19 17:29:00 編輯過 |
關鍵字查詢
相關文章
正在查詢... |