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(感谢@鹤冲天),相信随着时间推移,会有更多的Runtime出现,Mono也会变得更强大。到时,不止是Java,C#还有.NET平台下的各种语言(VB、C++/CLI、F#等)都可以实现“Write once, run anywhere”了。当然,还有随之而来的“Debug anywhere”(笑)。

(完)

Conmajia 2012

时间: 2024-11-09 18:13:43

Write Once, Run Anywhere:这不是Java,这是C#的相关文章

与大家分享robotium一个小问题。Test run failed:Instrumentation run failed due to 'java.lang.ClassNotFoundException'

今天和大家分享robotium一个小问题. 我们在运行自已经搭好的框架时,有可能会出现一个找不到类的错误(如上图所示). 问题是重签名工具给出的activity有误,这时我们可以用Appt命令查看重签名后的apk的activity,这个才是正确的. 1.进入到SDK安装目录下有Appt.exe程序的文件夹 2.输入命令aapt dump badging D:\qq.unar_debug.apk.(注:命令+apk的存放路径) 3.可查看包名.版本.开发用的sdk的版本 4.查看activity

面试贴:java异常小结

java的异常处理在面试中通常是个敏感的话题,这里我从整体框架方面稍微作一下我的小结. java的异常都继承Throwable这个类,也就是都可以抛出来的异常,在这个祖先类下,又分为如下子类: 1.Error类,这类异常通常是由系统产生的,也就是系统的错误,是我们程序员控制不了也处理不了的. 2.Exception类:这个类称为可以处理的异常,又分为两种 (1)一种是必须逮的异常,例如我们对文件进行I/O读取时,有可能文件会不存在,会读不到,引起这个错误的不是你编的程序本身,而是出在文件上,因此

eclipse run as 后边没有java application的选项

在要运行的项目中选择一个类,添加一个主函数即可.public static void main(String[] args) { }

JAVA “Run as administrator” “UAC disabled” alternative solution

Technorati 标签: psexec,run as administrator,UAC java.io.IOException: Cannot run program "psexec.exe": CreateProcess error=740, The requested operation requires elevation    at java.lang.ProcessBuilder.start(Unknown Source)    at java.lang.Runtime

java+opencv+intellij idea实现人脸识别

首先当然是需要安装opencv了,我用的是opencv2.4.13.下载完之后就可以直接安装了,安装过程也很简单,直接下一步下一步就好,我就不上图了. 接下来在opencv下找到jar包,比如我直接安装在c盘,我的jar包在C:\opencv\build\java中. 然后将jar包拷贝到lib目录中,并且在idea中配置 接着在opencv的路径下找到lbpcascade_frontalface.xml.比如我的就是C:\opencv\sources\data\lbpcascades.然后将其

深入理解java注解的实现原理

今天将从以下4个方面来系统的学习一下java注解 什么是注解 注解的用途 注解使用演示 注解的实现原理 1,什么是注解 注解也叫元数据,例如我们常见的@Override和@Deprecated,注解是JDK1.5版本开始引入的一个特性,用于对代码进行说明,可以对包.类.接口.字段.方法参数.局部变量等进行注解 一般常用的注解可以分为三类: 一类是Java自带的标准注解,包括@Override(标明重写某个方法).@Deprecated(标明某个类或方法过时)和@SuppressWarnings(

最常见的15个Java多线程,并发面试问题

例如,用于DMA交易的高容量和低延迟电子交易系统通常是并发的.大多数情况下,他们专注于微秒延迟,这就是为什么拥有如何有效地最小化延迟和提高吞吐量知识是如此重要. 这些是我最喜欢的关于Java的线程面试问题.我没有提供这些线程访谈问题的答案,但我会尽可能给你一个提示.我会更新帖子就详细的答案,就像我最近在Java中发布的10个Singleton面试问题一样. 15 Java Thread Interview Questions and answers 无论如何,这里是一些常见的Java多线程和并发

Java数据结构——带权图

带权图的最小生成树——Prim算法和Kruskal算法 带权图的最短路径算法——Dijkstra算法 package graph; // path.java // demonstrates shortest path with weighted, directed graphs 带权图的最短路径算法 // to run this program: C>java PathApp ////////////////////////////////////////////////////////////

java.lang.NoClassDefFoundError: com/opensymphony/x

问题:严重: Unable to read class [com.spml.action.AddUserAction]java.lang.NoClassDefFoundError: com/opensymphony/xwork2/util/finder/DefaultClassFinder$InfoBuildingVisitor    at com.opensymphony.xwork2.util.finder.DefaultClassFinder.readClassDef(DefaultCla