討論:“Mono是個跨平臺的.NET”是否是個正確的說法
Thorbjorn在提問中認為Mono并不能稱作是跨平臺的.NET,理由如下:
- OpenJDK等Java提供商都通過了官方的Sun TCK來保證正常工作,Mono似乎并沒有通過Microsoft TCK。
- Mono的發布總是落后于.NET,那么目前它又對.NET支持到什么程度呢?
- 如WinForm等GUI工具是否可以在Mono下正常工作?
- 商業用戶不會將開源框架作為備選方案。
用戶sparkie首先回應了以上幾點疑問:
首先,CLI(Common Language Infrastructure)和.NET是有區別的,前者是公開標準,而后者是微軟對這一標準的實現,Mono則是CLI的又一實現,它從來不是“可移植的.NET”。同樣,C#也是一個公開標準,也不和.NET綁定在一起。
Mono相對于.NET是有些落后,但也只有一丁點而已。Mono可以運行C# 4.0的代碼(最新的.NET版本),與此同時微軟最近把所有的DLR代碼都開源了(使用Apache 2.0授權協議),這意味著mono可以直接使用IronPython,IronRuby,同時F#也不久前也已經開源,再加上微軟都會定期發布.NET的CTP版本,因此Mono開發人員幾乎可以時刻和.NET保持同步。.NET中的部分工具和擴展,如Code Contract等等,它們并沒有mono中的完整實現,不過它們的使用并不廣泛。如果這些擴展變得流行起來了,那么Mono也會提供對應的實現。
WinForm沒有得到完整的移植,因為它們是.NET的特性功能,而并非CLI的一部分。CLI中并沒有定義特定的組件庫。有一些組件庫是跨平臺的,例如GTK#和Silveright,如果你從編寫應用程序的一開始就考慮到可移植性,那就不應該使用WinForm/WPF。此外,Mono提供了一個很薄的封裝層,現有的WinForm應用程序可以可以比較容易地移植為GTK#(不需要完全重寫)。
Mono提供了一個工具:Mono Migration Analyser(MoMA),它能檢查一個.NET應用程序能否移植到Mono上(如,是否使用了不可移植的類庫,或是P/Invoke)。
對于不愿意使用開源產品的商業應用,Mono可以使用另一種授權方案,這時候Mono代碼的歸屬權則交由Novell負責,此時授權方案便不是LGPL了。
因此,如果要考慮“.NET可否移植”這個命題,我想如果你從一開始就考慮到框架的可移植性問題,則它是成立的。但如果換個說法“我有個使用.NET開發的Windows應用程序,它應該可以在Mono上運行”,那就不正確了——不過Mono讓移植這樣的應用程序變得簡單許多。
隨后Lloeki談論了他的工作方式:
除了技術方面的因素以外,關鍵還是在于編寫代碼的方式。
無論是哪種跨平臺的應用程序(例如Java,Python,Ruby……),如果在寫代碼時不考慮可移植性,那么你應該假設這些代碼可以直接跨平臺執行的可能性為零(即使實際上這樣的可能性要高出許多)。你無法隨便拿到一個程序集就保證它能在Mono下正確執行。
不過對于一個新項目(或是你可以輕易重構的項目),選擇.NET/Mono作為可移植的方案之一則是明智的,不過對于跨平臺的代碼來說,你還是需要不斷地進行測試。如果你使用持續集成,那么只要簡單的創建一個Mono構建的節點即可。只要養成良好的習慣(例如路徑的分隔符),很多問題可以在開發階段就解決掉,而絕大部分代碼只要使用單元測試以及其他一些常見的實踐方式,再加上一點點先期規劃就能得到很好的跨平臺性。剩下的,例如平臺相關的代碼(如P/Invoke),則可以通過封裝,為不同平臺提供針對性的實現。這樣產出的項目,幾乎不會付出額外的代價就能得到很好的移植性。
當然,使用一個Mono中不存在或是不兼容的類庫則另當別論,不過就我的個人而言還沒有遇到這樣的情況。這些是我們在工作中實際用到的做法,我可以放心的聲稱“.NET+Mono”是跨平臺的解決方案。
對于Mono于.NET功能的支持程度,Robert和Michael談到:
我用過Mono,我認為它就和其他開源平臺一樣好,只不過不是微軟直接支持的而已。如果你能接受Clojure或Scala這樣的開源項目,那么Mono也能讓你滿意。Mono對于.NET的支持程度可以參考Mono Roadmap頁面。Mono并不等同于.NET,它們有或多或少的區別,例如現在你還無法使用Entity Framework。
Mono不是.NET的移植品,有些技術是Mono不會或不打算實現的(如Workflow Foundation或WPF),此外它們還提供了微軟.NET外的其他一些技術,例如SIMD擴展。簡單地說,Mono和微軟.NET是基于相同基礎——CIL和BCL——的兩個不同項目。
在討論中,Mono創建者Miguel de Icaza給出了最為詳細的回應:
“.NET是否跨平臺”是一個模糊的說法,無論是框架本身還是整體環境都在不斷改變。
簡單地說,作為.NET的基礎架構,CLI標準是跨平臺的,但如果要在不同平臺上得到最好的體驗,則勢必要使用各自平臺上有針對性的API。CLI技術家族從來沒有試著要“一次編寫,到處執行”,好比電話和大型機的區別實在是太大了。與其為不同平臺提供統一的API和運行時,不如各自平臺上的最佳體驗提供最正確的工具。試想那些非Windows PC或Unix服務器的程序員,要知道如今已經出現了游戲設備,移動電話,機頂盒,分布式集群等太多激動人心的平臺。
微軟的.NET框架不是跨平臺的產品,它只能運行在Windows上。其他系統上還有一些.NET框架的變體,例如Windows Phone 7,XBox 360和瀏覽器中的Silverlight,它們都有些許不同的配置(Profile)。
如今你已經可以在各個主流的操作系統,電話,移動設備,嵌入式系統或是服務器上使用基于.NET的技術,以下是各種CLI實現的列表,雖不完整,但應該可以覆蓋99%的情況:
- 基于x86和x86-64的計算機:
- Windows:一般來說你會使用.NET或Silverlight,不過你也可以使用完整的Mono。
- Linux, BSD或Solaris:完整的Mono或Silverlight。
- MacOS X:完整的Mono或Silverlight。
- Android:Mono及Android的子集。
- ARM計算機:
- Windows Phone 7:Compact Framework 2010。
- Windows 6.5及更早:早期的Compact Framework。
- Android設備:Mono/Android。
- PowerPC計算機:
- 在Linux,BSD或Unix操作系統上使用完整的Mono功能。
- 在嵌入式系統中使用Mono,如PS3,Wii。
- 在XBox36上運行Compact Framework。
- S390, S390x, Itanium, SPARC計算機:
- 完整的Mono支持
- 其他嵌入式操作系統:
- .NET MicroFramework或Mono的移動配置。
有時候相同的代碼很難四處運行。例如XNA代碼不會在每個桌面上運行,反之亦然。為了.NET不同的配置里運行,你需要修改些許代碼。以下是我所了解的一些配置:
- .NET 4.0配置
- Silverlight配置
- Windows Phone 7配置
- XBox360配置
- Mono核心配置:與.NET配置相同,可以在Linux,MacOS X,Solaris,Windows和BSD里使用。
- .NET Micro Framework
- Mono的iPhone配置
- Mono的Android配置
- Mono的PS3配置
- Mono的Wii配置
- Moonlight配置(與Silverlight兼容)
- Moonlight擴展配置(Silverlight和完整的.NET 4 API)
以上配置都有多多少少的不同,這不是壞事。每個配置的設計都適應其平臺,去除任何一個都是不明智的。例如,Silverlight API可以控制瀏覽器,這不關電話什么事;由于缺少合適的支持,XNA的著色功能對PC硬件也沒有多少意義。你越早認識到.NET不是個將開發人員綁定在特定硬件或平臺上的解決方案,就能越早成為更好的開發人員。
這意味著,有些API或解決方案可以在多個平臺中使用,例如ASP.NET可以用在Windows,Linux,Solaris,MacOS X上,因為.NET和Mono都提供了這些API。同時,ASP.NET則無法在某些微軟支持的平臺上使用,例如XBox或Windows 7,也不支持Mono的Wii和iPhone配置。
其他解決方案的本質也是一樣的。要完整列出這些技術需要一張復雜的表格,我不知道如何在這里表現出來,不過這里有個特定技術與特定平臺的列表:
核心運行時引擎(所有平臺):
- Reflection.Emit支持:除WP7、CF、XBox、MonoTouch和PS3外的所有平臺 。
- CPU SIMD支持:Linux,、BSD、Solaris及MacOS X。即將支持PS 3、MonoTouch和MonoDroid。
- Continuations - Mono.Tasklets:Linux、BSD、Solaris、MacOS、PS3及Wii。
- 程序集卸載:只有Windows。
- VM注入:Linux、BSD、MacOS X及Solaris。
- DLR:Windows、Linux、MacOS X、Solaris及MonoDroid。
- 泛型:在iPhone和PS3上存在一些限制。
語言:
- C# 4:所有平臺。
- C# 編譯器即服務:Linux、MacOS、Solaris、BSD及Android。
- F#、IronRuby及IronPython:除WP7、CF、Xbox、MonoTouch及PS3外的所有平臺。
服務器技術:
- ASP.NET:Windows、Linux、MacOS、BSD及Solaris。
- ADO.NET:所有平臺
- LINQ to SQL:所有平臺
- Entity Framework:僅Windows
- XML核心技術:所有平臺
- XML序列化:除WP7,CF和XBox外的所有平臺。
- LINQ to XML:所有平臺
- System.Json:Silverlight,Linux,MacOS,MonoTouch,MonoDroid(譯注:可移植到其他平臺)
- System.Messaging:Windows、Linux、MacOS和Solaris的支持則需要RabbitMQ。
- .NET 1 Enterprise Services:僅Windows。
- WCF:完整版僅支持Windows。Silverlight、Solaris、MacOS、Linux、MonoTouch、MonoDroid支持其自己。
- Windows Workflow:僅Windows。
- Cardspace identity:僅Windows。
GUI技術:
- Silverlight:Windows、Mac和Linux(Moonlight)
- WPF:僅Windows
- Gtk#:Windows、Mac、Linux及BSD
- Windows.Forms:Windows、Mac、Linux和BSD
- MonoMac - 原生Mac集成:僅Mac
- MonoTouch - 原生iPhone集成:僅iPhone/iPad
- MonoDroid - 原生Android集成:僅Android
- Media Center API:僅Windows
- Clutter:Windows和Linux
圖像類庫:
- GDI+:Windows、Linux、BSD及MacOS
- Quartz:MacOS X、iPhone及iPad
- Cairo:Windows、Linux、BSD、MacOS、iPhone、iPad、MacOS X、PS3及Wii
Mono類庫 - 跨平臺,可以在.NET里使用,不過需要手動編譯:
- C# 4編輯器及服務
- Cecil - CIL操作,工作流,CIL探測,鏈接器
- RelaxNG類庫
- Mono.Data.* 數據提供者
- 完整的System.Xaml(用于安裝程序,.NET沒有提供這個技術)
MonoTouch為iPhone上運行的Mono,MonoDroid為Andriod上運行的Mono。PS3和Wii的移植只供索尼和任天堂認證的開發人員使用。
在討論中Miguel de Icaza還表示,IBM至少完成了兩個針對AIX的Mono移植,不過他們的移植團隊沒有得到反饋其成果的許可。