我在Visual Studio和.NET中使用过C#,我在openSUSE Linux上玩过Mono,但我真的不明白它是如何工作的.
如果我在.NET上的Windows中编写应用程序,这与Mono有什么关系?我不能在没有Wine的情况下在Linux上执行Windows .exe文件,因此它无法帮助我执行在Windows中开发的应用程序.
纯粹是为了在Linux(和其他)上使用.NET库来实现跨平台开发更容易吗?例如,如果我是一家企业并且想要接触Linux客户,但是真的想使用.NET,那么Mono应该是我的选择吗?或者还有一些我想念的东西?
这是一个老问题(已经选择了答案)但我不相信这个问题确实得到了很好的回答.
首先,一点背景......
.NET如何工作?
传统的Windows .EXE文件是一个二进制文件,它表示计算机可以理解的一系列机器语言指令,并调用Win32 API,它们是Windows的一部分,提供应用程序可以利用的服务.使用的机器语言非常特定于您的计算机类型,Win32调用使可执行文件非常依赖于Windows..NET可执行文件不是那样的.
重要的是要意识到.NET可执行文件(.EXE文件)实际上不是本机Windows应用程序.Windows本身不了解如何在.NET可执行文件中运行代码.您的计算机也不理解它.
与Java类似,.NET应用程序由称为CIL(通用中间语言)的语言组成,您可以将其视为理想化计算机的机器语言,而这种计算机实际上并不存在.在.NET中,这种理想化机器的软件实现称为公共语言运行时(CLR).Java世界中的等价物称为Java虚拟机(JVM).在Java中,等效于CIL的称为Java字节码.CIL有时称为MSIL(Microsoft中间语言).
CIL设计为在CLR(理想化的机器)上运行,但在平台上是独立的,这意味着CIL不关心您拥有什么样的计算机或运行的操作系统.
正如您需要在要运行Java的每个平台上使用Java JVM的本机版本一样,您需要CLR的本机版本才能运行.NET CIL可执行文件.CLR是一个本机Windows应用程序,就像上面描述的传统Win32 EXE文件一样.CLR本身特定于Windows实现和计算机体系结构的运行.
无论你开始使用什么.NET语言(C#,VisualBasic,F#,IronPython,IronRuby,Boo等),它们都会被编译成CIL字节码.您可以轻松地将CIL程序"反汇编"为一种易于人类可读的面向对象汇编语言.您可以直接在CIL中编写程序,但很少有人这样做.
在Windows上,CLR在您运行可执行文件时正确编译此CIL代码实时(JIT) - 就在代码实际运行之前.这意味着CIL字节码被转换(编译)为在您的计算机上本机运行的实际机器代码.CLR的这一部分称为JIT编译器,或者通常只称为JIT.
到目前为止,Microsoft已发布了四个版本的CLR:1.0,1.1,2.0和4.0.如果要运行针对该运行时的.NET可执行文件,则需要在计算机上安装正确版本的CLR.CLR 2.0支持.NET 2.0,3.0和3.5应用程序.对于其他版本的.NET,.NET版本可以完全映射到CLR版本.
除了JIT/CLR之外,.NET还提供了许多库(程序集),这些库构成了.NET框架的其余部分,并提供了.NET应用程序可以调用的大量功能和服务.绝大多数这些程序集都是在CLR上运行的纯CIL代码.在Windows上,一些人也会调用Win32 API.安装.NET时,您正在安装CLR,类库(框架)和一堆开发工具.每个版本的CLR通常都需要一整套这些"框架"程序集.某些版本的.NET(例如3.0和3.5)添加了额外的框架程序集,而没有更新CLR或与该CLR关联的现有程序集.
提供Windows .EXE文件的可移植可执行文件(PE)文件格式包含描述可执行文件的标头,并将文件标识为.NET文件或本机Win32文件.当Windows尝试运行.NET文件时,它会看到此标头并代表您自动调用CLR.这就是.NET EXE文件似乎在Windows上本机运行的原因.
好吧,Mono如何工作?
Mono在Linux,Mac和其他平台上实现了CLR.Mono运行时(CLR)是一种本机应用程序,主要使用C语言编写,并编译为计算机系统的机器语言代码,用于运行.与Windows一样,Mono运行时特定于操作系统和您正在使用的机器类型.
就像在Windows上一样,Mono运行时(CLR)将.NET可执行文件中的CIL字节码及时编译为计算机可以理解和执行的本机代码.通过这种方式,.NET文件就像Linux一样"本机",就像Windows一样.
要将Mono移植到新架构,您需要移植JIT/CLR.这就像将任何本机应用程序移植到新平台一样.
.NET代码在Linux或Mac上运行的程度实际上只是CLR在这些系统上的实现情况.从理论上讲,Mono CLR可以在这些系统上执行.NET代码,比Windows上的MS版本更好.在实践中,MS实现通常是优越的(尽管不是在所有情况下).
除了CLR之外,Mono还提供了构成.NET框架的大多数其余库(程序集).与Microsoft的.NET版本(实际上更是如此)一样,Mono程序集也以CIL字节码的形式提供.这样就可以从Mono获取*.dll或*.exe文件,并在Windows,Mac或Linux上不加修改地运行它,因为CIL是这些系统上CLR实现的"本机"语言.
就像在Windows上一样,Mono支持多个版本的CLR和相关的程序集:
Mono的早期版本(1.2之前?)仅支持CLR 1.0或1.1.在它自己的2.0版本之前,Mono不支持2.0框架的大块.
最高版本2.4的Mono版本支持CLR 1.1和CLR 2.0应用程序.
从Mono 2.6开始,添加了CLR 4.0,但CLR 2.0仍然是默认值.
从Mono 2.8开始,CLR 4.0成为默认值,不再支持CLR 1.1.
Mono 2.10继续使用CLR 4.0作为默认值,也支持CLR 2.0.
就像真正的.NET(但在更少的情况下),有一些Mono程序集调用本机库.为了使System.Drawing程序集在Mono上运行,Mono团队编写了一个Linux程序来模拟Linux上Win32 API的GDI +部分.这个库叫做'libgdiplus'.如果你从源代码编译Mono,你会发现你需要构建这个'libgdiplus'文件才能构建'mono'.您在Windows上不需要"libgdiplus",因为Win32 API的GDI +部分已经是Windows的一部分.Mono到新平台的完整端口也需要移植这个'libgdiplus'库.
在.NET库的设计受到Windows设计过度影响而且不适合Mac或Linux等系统的领域,Mono团队已经编写了.NET框架的扩展.Mono扩展也只是CIL字节码,通常在.NET上工作得很好.
与Windows不同,Linux通常不会检测.NET可执行文件并默认启动CLR.用户通常必须通过键入"mono appname.exe"或类似名称直接运行CLR.这里'mono'是实现CLR的应用程序,'appname.exe'是包含要执行的.NET代码的EXE文件.
为了使用户更容易,Mono应用程序通常包含在启动CLR的shell脚本中.这隐藏了CLR正在Windows中使用的事实.当遇到使用PE文件格式的文件时,也可以告诉Linux启动CLR.这通常不会这样做,因为PE文件格式也用于本机Win32 Windows可执行文件,当然CLR(Mono)不支持.
没有技术上的理由说明为什么Linux不能使用PE启动器,然后启动一个能够理解本机Windows代码(如Wine)或CLR(Mono)的系统.据我所知,这根本就没有完成.
来来回回
任何坚持"完全托管"代码的.NET代码,这意味着它不会调用非.NET代码,在所有平台上都可以在Mono上正常运行.我经常在Linux和Mac上使用Windows中编译的.NET程序集(我没有代码).
我也可以使用我在Mono上编译的任何代码并在Windows上的.NET上运行.我可以为客户端提供一些我使用Mono编译的代码,如果他在32位或64位Windows上则不用担心.客户端确实需要安装正确版本的.NET(正确的CLR).CLR 2.0已经存在了很长时间,您可以打赌几乎所有Windows用户都安装了它.Mono编译器和其他代码也只是CIL可执行文件,因此如果您愿意,它们可以在Windows上正常运行.
单声道兼容性非常好,可以从实际的MS版本的.NET中获取大量实际Microsoft代码(如ASP.NET MVC)(在合法的情况下这样做)并在Mac或Linux上运行.总的来说,Mono团队在实现CLR和框架的其余部分(类库/程序集)方面做得非常出色.
ASP.NET
在Windows上,Internet Information Server(IIS)知道如何调用CLR来执行.NET作为Web应用程序的一部分.在Linux/Mac上有一个Apache模块(mod_mono),它提供与Apache webserver类似的功能.此应用程序是用C语言编写的,还必须移植到新的体系结构中.
移植单声道
本讨论已经确定了构建为"本机"可执行文件的Mono部分,并且必须存在于要运行.NET应用程序的系统上.
CLR(包括JIT编译器) - 通常称为Mono
libgdiplus(适用于本身不支持GDI + API的系统[仅适用于Windows])
mod_mono(允许Apache调用.NET Web应用程序的CLR)
这三个组件通过添加类库提供了一个.NET环境,该环境看起来是您需要运行的.NET可执行文件的"本机".
这就是Mono的工作原理.
Windows EXE包含多个"部件".简而言之,.net代码(= MSIL)只是EXE的一部分,EXE中还有一个"真正的"原生Windows部分,它作为.net Framework的某种启动器,然后执行MSIL.
Mono只需要使用MSIL并执行它,忽略原生Windows Launcher的东西.
同样,这是一个简化的概述.
编辑:我担心我对深层细节的理解对于非常详细的细节来说还不够好(我大致知道PE标题是什么,但不是真正的细节),但我发现这些链接很有帮助:
NET装配结构 - 第二部分
.NET Foundations - .NET程序集结构
实际上,您可以在Linux上使用Mono运行.NET .exe文件.这不需要Wine.事实上,Mono将程序编译为.exe文件,可以在Linux上运行Mono,也可以在Windows上运行.