注意 , 本文目的并非挑起语言之争 。 虽然有为 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 uFlags
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” ( 笑) 。
( 完)
© Conmajia 2012
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂