Write Once, Run Anywhere:這不是Java,這是C#
註意,本文目的並非挑起語言之爭。雖然有為C#平反之意,但主要還是介紹Mono並進行簡單的測試。
UPDATED: 25th August 2012
更新了「Compile Once, Run Anywhere:跨平臺的終極目標」一節。
Conmajia 2012
引言
“Write once, run anywhere”(一次編寫,到處運行,WORA),有時也寫成“Write once, run everywhere”(WORE),是Sun Microsystem(於2010年被Oracle收購)為宣傳Java語言的跨平臺特性而提出的口號。在理想情況下——當然常常是不可能的——將Java語言寫成的程序編譯為標準的字節碼(bytecode),就可以運行在支持Java虛擬機(JVM)的任何設備上。
很多半吊子的Java“專家”常常用這點來擠兌.NET的使用者,說他們“被微軟綁架了,只有JVM這種業界標準才能跨平臺”。
真實的情況是什麽呢?一方面,真正的Java開發者不斷抱怨著“Write once, debug anywhere"(一次編寫,到處調試),另一方面,越來越多的人認識到.NET的本質實際是CLI/CTS,也是業界標準,CLR也是虛擬機。所以,總是在“跨平臺”的能力上突出Java而貶低.NET,已經是落伍和壓根不懂的表現了。
最近我因為電腦運行速度慢,於是刪除了Windows,轉而安裝Linux Mint(一個基於Ubuntu的Linux發行版)。
在Linux環境下,有很出名的.NET運行時——Mono。
Mono的大名,搞.NET的朋友相信都知道。它使.NET程序在Linux下有了跨平臺運行的可能。Mono目前支持到.NET v4.0,已經逐漸趨於穩定和流行了(參見《兼容性》一節)。由於我只會C#(慚愧),因此需要在Linux下開發和運行.NET程序,於是安裝Mono。
$ sudo apt-get install mono-gmcs libmono-system-data2.0-cil libmono-system-ldap2.0-cil libmono-system-messaging2.0-cil libmono-system-runtime2.0-cil
這裏說個題外話。盡管對於已經廣泛使用的技術(如.NET)而言,運行時的文件大小已經沒有太大的討論意義,但是仍然有人拿這個說事,以此說明.NET Framework是如何如何不好(其實Win Vista之後這已經不算事了)。那麽Mono的表現又如何呢?
Mono的完全安裝大小為78MB(Java最小安裝尺寸95MB),而Mono最小化安裝之需要7MB。(參考文獻:http://www.infoq.com/cn/news/2007/07/Mono-Runtime-Size)
為了能夠方便開發,我直接安裝了MonoDevelop。這是Windows上大名鼎鼎的開源.NET IDE SharpDevelop的Linux版本。
安裝命令如下:
$ sudo apt-get install monodevelop
Linux下編譯
下面是幾個簡單的程序測試。註意,這裏的程序代碼在Windows下是完全可以運行的。
命令行程序
1 using System; 2 3 namespace Test 4 { 5 class Program 6 { 7 static void Main() 8 { 9 Console.WriteLine("Hello Mono!");10 Console.ReadLine();11 }12 }13 }
運行結果
WinForm程序
1 using System; 2 using System.Windows.Forms; 3 4 namespace test 5 { 6 public class MainForm:Form 7 { 8 TextBox textBox1; 9 Button button1;10 public MainForm ()11 {12 textBox1=new TextBox();13 textBox1.Text="Text here...";14 textBox1.Location=new System.Drawing.Point(10,10);15 button1=new Button();16 button1.Text="Click me.";17 button1.AutoSize=true;18 button1.Location=new System.Drawing.Point(10,40);19 this.Controls.Add (textBox1);20 this.Controls.Add (button1);21 } 22 }23 }
運行結果
是不是很意外?Linux下面可以直接運行WinForm的程序。就是這麽方便。演示代碼是在Linux下編譯的,還不能證明“Write once, run anywhere”,那麽,就直接運行Windows下編譯出來的exe又如何?我們來試試編譯型程序跨平臺的終極目標:Compile once,run anywhere
Compile Once, Run Anywhere:跨平臺的終極目標
下面是我之前在Windows下用Visual Studio和SharpDevelop編譯的exe不做任何處理(也沒法處理)直接運行。
首先是《蜂巢大戰》,先來看看Windows下運行的效果。
然後是在Linux下運行。
註意:因為默認.exe是和歸檔管理器關聯的,所以需要選擇打開方式為“Mono Runtime”。
運行效果如下
經測試各種功能正常。說明GDI+工作正常,ToolStrip等控件也運行正常。
再來看看我最近發表的另一個程序:《InvokeHelper》。
Windows下是這樣的
在Mono環境下運行是這個效果
說明和線程相關的功能工作正常。
再來是和Windows API相關的。其實用腳指頭想也是不可能的(不光C#,隨便什麽語言都一樣,這種和平臺API強相關的,怎麽可能“跨平臺”呢)。
《獲取系統圖標》,這個程序使用了SHGetFileInfo這個Windows API:
1 [DllImport("Shell32.dll")]2 static extern int SHGetFileInfo(3 string pszPath,4 uint dwFileAttributes,5 ref SHFILEINFO psfi,6 uint cbFileInfo,7 uint uFlags8 );
在Windows中工作正常
在Linux下如何呢?運行下試試:
調用打開文件對話框正常,但是一旦運行到Windows API就自動退出。所以,跨了平臺後,和平臺(Win)相關的API不能用了,這也是理所當然的。C#和Java都沒辦法跳掉這樣的命運(笑)。
兼容性
這裏有一個例子展示了目前MONO的一些兼容性情況:支持範型(2.0+)和var(3.0+)。
官方給出的兼容性可以在這個頁面察看:http://www.mono-project.com/Compatibility
目前最新的Mono is 2.10.8. (Released December 19th, 2011)已經可以支持.NET 4.0版本。參見下圖:
移植
選用不同的平臺,遲早要面對移植問題。由於CLI/CTS只規定了語言的基礎部分,因此各個運行時的實現有部分差異(參見上一節:兼容性)。所以Mono官方提供了一個叫做Mono Migration Analyzer(MOMA,摩碼)的移植輔助工具。這個工具可以直接告訴你將一個現成的基於Windows + Microsoft.Net的程序,移植到Win/Linux/Mac + Mono的可能性。
有時候實現一個小功能,實現方式其實有好多種,但有的實現方式是依賴於Windows API的,有的不是,在不影響性能的前提下,我們要優先選擇標準實現而不是特殊實現。這就是用Mono做項目的成功秘訣。
總結
目前比較有名的非Windows平臺下.NET虛擬機/運行時暫時只有Mono、Portable.NET([email protected]),相信隨著時間推移,會有更多的Runtime出現,Mono也會變得更強大。到時,不止是Java,C#還有.NET平臺下的各種語言(VB、C++/CLI、F#等)都可以實現“Write once, run anywhere”了。當然,還有隨之而來的“Debug anywhere”(笑)。
(完)
Conmajia 2012
Write Once, Run Anywhere:這不是Java,這是C#