注意,本文目的并非挑起语言之争。虽然有为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。

  1. $ 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版本。

安装命令如下:

  1. $ sudo apt-get install monodevelop

Linux下编译

下面是几个简单的程序测试。注意,这里的程序代码在Windows下是完全可以运行的。

命令行程序

  1. 1 using System;
  2. 2
  3. 3 namespace Test
  4. 4 {
  5. 5 class Program
  6. 6 {
  7. 7 static void Main()
  8. 8 {
  9. 9 Console.WriteLine("Hello Mono!");
  10. 10 Console.ReadLine();
  11. 11 }
  12. 12 }
  13. 13 }

运行结果

WinForm程序

  1. 1 using System;
  2. 2 using System.Windows.Forms;
  3. 3
  4. 4 namespace test
  5. 5 {
  6. 6 public class MainForm:Form
  7. 7 {
  8. 8 TextBox textBox1;
  9. 9 Button button1;
  10. 10 public MainForm ()
  11. 11 {
  12. 12 textBox1=new TextBox();
  13. 13 textBox1.Text="Text here...";
  14. 14 textBox1.Location=new System.Drawing.Point(10,10);
  15. 15 button1=new Button();
  16. 16 button1.Text="Click me.";
  17. 17 button1.AutoSize=true;
  18. 18 button1.Location=new System.Drawing.Point(10,40);
  19. 19 this.Controls.Add (textBox1);
  20. 20 this.Controls.Add (button1);
  21. 21 }
  22. 22 }
  23. 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. 1 [DllImport("Shell32.dll")]
  2. 2 static extern int SHGetFileInfo(
  3. 3 string pszPath,
  4. 4 uint dwFileAttributes,
  5. 5 ref SHFILEINFO psfi,
  6. 6 uint cbFileInfo,
  7. 7 uint uFlags
  8. 8 );

在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”(笑)。

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

  1. Android 下进行单元测试 Test run failed:Instrumentation run failed due to 'java.lang.ClassNotFoundException'

    废话不说,一直报错.网上介绍的都是缺少如下声明之类. 但注意的是工程配置是导出junit包, 路径为  project上右键 --> properties -> java build pa ...

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

    今天和大家分享robotium一个小问题. 我们在运行自已经搭好的框架时,有可能会出现一个找不到类的错误(如上图所示). 问题是重签名工具给出的activity有误,这时我们可以用Appt命令查看重签 ...

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

    Technorati 标签: psexec,run as administrator,UAC java.io.IOException: Cannot run program "psexec. ...

  4. ERROR: Java 1.7 or later is required to run Apache Drill.

    问题 Apache 的 drill 执行启动命令 drill-embedded 报错: ERROR: Java 1.7 or later is required to run Apache Drill ...

  5. Java的多线程机制系列:(二)缓存一致性和CAS

    一.总线锁定和缓存一致性 这是两个操作系统层面的概念.随着多核时代的到来,并发操作已经成了很正常的现象,操作系统必须要有一些机制和原语,以保证某些基本操作的原子性.首先处理器需要保证读一个字节或写一个 ...

  6. Java与C#的比较学习

    http://www.cnblogs.com/javathread/archive/2012/08/11/2634893.html 我在大学学的是C语言,自学和选修的是C++,刚毕业也搞过几天Jsp, ...

  7. [翻译]现代java开发指南 第二部分

    现代java开发指南 第二部分 第二部分:部署.监控 & 管理,性能分析和基准测试 第一部分,第二部分 =================== 欢迎来到现代 Java 开发指南第二部分.在第一 ...

  8. Flutter 初尝:从 Java 无缝过渡

    准备阶段 下载 Flutter SDK 新建 Flutter 文件夹,克隆 Flutter SDK: git clone -b beta https://github.com/flutter/flut ...

  9. JAVA常用基础知识点[继承,抽象,接口,静态,枚举,反射,泛型,多线程...]

    类的继承 Java只支持单继承,不允许多重继承- 一个子类只能有一个父类- 一个父类可以派生出多个子类这里写图片描述子类继承了父类,就继承了父类的方法和属性.在子类中,可以使用父类中定义的方法和属性, ...

随机推荐

  1. SpringCloud学习系列之七 ----- Zuul路由网关的过滤器和异常处理

    前言 在上篇中介绍了SpringCloud Zuul路由网关的基本使用版本,本篇则介绍基于SpringCloud(基于SpringBoot2.x,.SpringCloud Finchley版)中的路由 ...

  2. python读写xlsx

    1使用openpyxl库读写excel xlrd和xlwt处理的是xls文件,单个sheet最大行数是65535,如果有更大需要的,建议使用openpyxl函数,最大行数达到1048576.  如果数 ...

  3. js 常用排序

    1. 冒泡排序 原理:从第一个元素开始,把当前元素和下一个索引元素进行比较.如果当前元素大,那么就交换位置,重复操作直到比较到最后一个元素 function bubbleSort(arr) { if ...

  4. 阿里云ECS 自己搭建 hyperledger fabric的错误

    常常有在本地搭建没问题,到阿里云上跑的时候 fabric启动不成功的问题. 引用: https://yq.aliyun.com/articles/238940 解决方案 1.在e2e_cli 下有个d ...

  5. 洛谷P2522 [HAOI2011]Problem b(莫比乌斯反演)

    传送门 我们考虑容斥,设$ans(a,b)=\sum_{i=1}^a\sum_{j=1}^b[gcd(a,b)==k]$,这个东西可以和这一题一样去算洛谷P3455 [POI2007]ZAP-Quer ...

  6. [Xcode 实际操作]六、媒体与动画-(10)UIView视图翻转动的画制作

    目录:[Swift]Xcode实际操作 本文将演示翻转动画的制作. 在项目导航区,打开视图控制器的代码文件[ViewController.swift] import UIKit class ViewC ...

  7. LInux temp 目录太小不够用问题

    2013-10-18 11:01 可以自己建一个临时 目录看看 dev /#su - root #mkdir /opt/tmp #chown root /opt/tmp/ #chgrp root /o ...

  8. Etherscan API 中文文档-账号

    本文原文链接 点击这里获取Etherscan API 中文文档(完整版) 完整内容排版更好,推荐读者前往阅读. 账号(Account) 账号及地址相关的 API,接口的参数说明请参考Etherscan ...

  9. Awesome Blockchain 区块链技术导航

    区块链技术导航:收集整理最全面最优质的区块链(BlockChain)技术开发相关资源. 以后找不到文档资料的时候去导航站看看. 先亮个像,我长这样: 导航站内容 区块链开发所涉及的资源: 如 项目白皮 ...

  10. 【VueJS】sublime text3支持VueJS语法高亮显示插件vue-syntax-highlight

    1. sublime text3支持VueJS语法高亮显示插件vue-syntax-highlightgithub地址: https://github.com/vuejs/vue-syntax-hig ...