1. 程式人生 > >Write Once, Run Anywhere:這不是Java,這是C#

Write Once, Run Anywhere:這不是Java,這是C#

java

註意,本文目的並非挑起語言之爭。雖然有為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#