前言
我们知道,Mono 是 .NET Framework 跨平台的开源实现。Mono 的源代码就是金矿,等待我们去挖掘。
目前 Mono 的最新版本是 Mono 2.8.2,可以到 http://ftp.novell.com/pub/mono/sources/mono/ 下载 mono-2.8.2.tar.bz2,文件大小是30MB。可以参阅“在 Ubuntu 10.10 操作系统安装 Mono 2.8.2”一文。
现在,让我们来看看 Mono 是如何实现 .NET Framework Base Class Library 中的 System.Console 类的。Console 类在 CUI 应用程序中有着十分重要的作用。而且,从 .NET Framework 2.0 开始,Console 类除了实现基本的控制台输入/输出功能以外,还实现了诸如更改前景色和背景色等高级功能。下图就是一个例子:
Microsoft 实现的 Console 类只需要考虑 Windows 操作系统的控制台就行了,但是 Mono 的 Console 类就必须考虑跨平台了,要能够工作在 Windows 和 Unix 操作系统中。所以是比较复杂的。
准备在自己的工作目录下编译出 Console.dll 程序集
为了研究 Console 类的源代码,找出和 Console 类密切相关的源代码,我准备从 Console.cs 出发在自己的工作目录下编译出一个 Console.dll 程序集。我们来看看 Console 类的源代码位于 Mono 体系的什么位置:
ben@ben-1520:~$ cd src/mono-2.8.2
ben@ben-1520:~/src/mono-2.8.2$ find . -name Console.cs
./mcs/class/corlib/System/Console.cs
ben@ben-1520:~/src/mono-2.8.2$
哦,因为 Console 类定义于 .NET Framework 最核心的 mscorlib.dll 程序集,并且位于 System 命名空间。所以上面的命令就显示这样的结果了。
我们现在准备一个工作目录:
ben@ben-1520:~$ cd ~/work ben@ben-1520:~/work$ mkdir Console ben@ben-1520:~/work$ cd Console ben@ben-1520:~/work/Console$
先把上述 Console.cs 从 Mono 的源代码目录拷贝到工作目录中,然后使用 C# 编译器进行编译,根据出错信息来决定还要拷贝哪些文件。最终,发现需要 Mono 源代码 mcs/build/common、mcs/class/corlib/System 和 mcs/class/corlib/System.IO 目录下的 23 个 C# 源程序文件,在上面三个目录分别是 2 个、18 个和 3 个。我编写了一个如下内容的 mksrc.sh 脚本,用于将 Mono 2.8.2 的源代码与 Console 类相关的源文件复制到工作目录中:
01: cd ~/work/Console 02: rm -rf mcs 03: mkdir mcs 04: mkdir mcs/build 05: mkdir mcs/build/common 06: mkdir mcs/class 07: mkdir mcs/class/corlib 08: mkdir mcs/class/corlib/System 09: mkdir mcs/class/corlib/System.IO 10: cd ~/src/mono-2.8.2/mcs/build/common 11: cp Locale.cs MonoTODOAttribute.cs ~/work/Console/mcs/build/common 12: cd ~/src/mono-2.8.2/mcs/class/corlib/System.IO 13: cp Stream.cs UnexceptionalStream*er.cs ~/work/Console/mcs/class/corlib/System.IO 14: cd ~/src/mono-2.8.2/mcs/class/corlib/System 15: cp Buffer.cs Control*.cs CStream*.cs *Term*.cs *Console*.cs ~/work/Console/mcs/class/corlib/System 16: cd ~/work/Console/mcs/class/corlib/System 17: rm ConsoleColor.cs ConsoleKey.cs ConsoleModifiers.cs ConsoleSpecialKey.cs 18: cd ~/work/Console
从 Stream.cs 中分离出 NullStream 类的源代码
在 Mono 的源代码的 Stream.cs 文件中,包含以下三个类:
- public abstract class Stream : MarshalByRefObject, IDisposable
- internal class NullStream : Stream
- internal class SynchronizedStream : Stream
因为我们需要用到 NullStream 类,所以将工作目录中 mcs/class/corlib/System.IO/ 目录下的 Stream.cs 改名为 NullStream.cs,然后在该文件中删除另外两个类的源代码,只保留 NullStream 类的源代码。
虽然 Mono 是一项伟大的开源工程,大师们写的代码也非常精彩。但是在这里还是有点疏忽了。如果 Mono 的源代码的 Stream.cs 文件中只包含 Stream 类,而把 NullStream 类的源代码放在 NullStream.cs 文件中,把 SynchronizedStream 类的源代码放在 SynchronziedStream.cs 文件中。我们也就可以直接使用 NullStream.cs 文件了,不用象现在一样又是改名,又是删除代码。
编写辅助代码
现在让我们编写一些简单的辅助代码,以便能够编译生成 Console.dll 程序集文件。
ben@ben-1520:~/work/Console$ mkdir Skyiv ben@ben-1520:~/work/Console$ cd Skyiv ben@ben-1520:~/work/Console/Skyiv$ gedit AssemblyInfo.cs Environment.cs ExtensionMethods.cs MonoIO.cs Stub.cs ben@ben-1520:~/work/Console/Skyiv$
下面就是 AssemblyInfo.cs,仅仅是简单地使用 CLSCompliantAttribute 标记程序集,指示该程序集符合公共语言规范。
1: using System; 2: 3: [assembly:CLSCompliant(true)]
下面就是 Environment.cs,主要是因为在 Console.cs、ConsoleDrivers.cs 这两个源程序中使用了 Environment 静态类的 IsRunningOnWindows 静态属性,而这个属性是 internal 的。所以我们必须自己提供一个,不然程序无法通过编译。我们还必须提供在其他源程序中有使用的 NewLine 属性以及 Exit 和 GetEnvironmentVariable 方法。这三个成员原来是 public 的,但是我们自己用的话,使用 internal 来修饰是没有问题的。注意,IsRunningOnWindows 属性指示是否运行在 Windows 操作系统中,这在 Microsoft 的 .NET Framework 中是没有的,因为 Microsoft 的实现总是运行在 Windows 操作系统中。Mono 为了跨平台才需要这个属性。
01: namespace System 02: { 03: static class Environment 04: { 05: internal static bool IsRunningOnWindows { get { return false; } } 06: internal static string NewLine { get { return "\n"; } } 07: internal static void Exit(int code) { } 08: internal static string GetEnvironmentVariable(string value) { return value; } 09: } 10: }
下面就是 ExtensionMethdos.cs,仅提供一个扩展方法,即用于 StreamReader 类的 DataAvailable 方法。在 Mono 的StreamReader 类中,DataAvailable 方法是 internal 的,所以我们必须自己提供一个。这个 DataAvailable 方法在 TermInfoDriver.cs 源程序中有使用。
01: namespace System.IO 02: { 03: static class ExtensionMethods 04: { 05: internal static bool DataAvailable(this StreamReader reader) 06: { 07: return reader.Peek() != -1; 08: } 09: } 10: }
下面就是 MonoIO.cs。这个 MonoIO 类在 Console.cs 和 ConsoleDriver.cs 源程序中有使用。很奇怪,如果不提供这个 MonoIO 类,在 Ubuntu 10.10 操作系统的 Mono 2.8.2 环境下是能够编译成功的,但在 Windows 操作系统的 .NET Framework 4 环境下无法编译成功。
1: namespace System.IO 2: { 3: static class MonoIO 4: { 5: internal static IntPtr ConsoleInput { get { return (IntPtr)0; } } 6: internal static IntPtr ConsoleOutput { get { return (IntPtr)1; } } 7: internal static IntPtr ConsoleError { get { return (IntPtr)2; } } 8: } 9: }
下面就是 Stub.cs,提供了 Encoding 和 TextWriter 类的一些 internal 静态成员,以及 FileStream 类的 internal 构造函数和一个隐式转换操作符,用以把我们的 Skyiv.Stub.FileStream 隐式转换为 System.IO.FileStream。这些东东都只在 Console.cs 源程序中使用。
01: using System; 02: using System.IO; 03: 04: namespace Skyiv.Stub 05: { 06: static class Encoding 07: { 08: internal static System.Text.Encoding UTF8Unmarked { get { return System.Text.Encoding.UTF8; } } 09: internal static void InternalCodePage (ref int code_page) { } 10: } 11: 12: static class TextWriter 13: { 14: internal static System.IO.TextWriter Synchronized(System.IO.TextWriter writer, bool neverClose) 15: { 16: return writer; 17: } 18: } 19: 20: sealed class FileStream 21: { 22: internal FileStream (IntPtr handle, FileAccess access, bool ownsHandle, int bufferSize, bool isAsync, bool isZeroSize) 23: { 24: } 25: 26: public static implicit operator System.IO.FileStream(FileStream value) 27: { 28: return null; 29: } 30: } 31: }
修改 Console.cs 源程序
现在,修改 Console.cs 源程序,对第 127、131、138、144、150 和 187 行共六处的 Encoding、TextWriter 和 FileStream 前面加上“Skyiv.Stub.”,以便调用我们自己的版本。
生成编译响应文件并编译
ben@ben-1520:~/work/Console/Skyiv$ cd .. ben@ben-1520:~/work/Console$ ls Skyiv/*.cs mcs/build/*/*.cs mcs/class/*/*/*.cs > make.rsp ben@ben-1520:~/work/Console$ gedit make.rsp ben@ben-1520:~/work/Console$ dmcs @make.rsp ben@ben-1520:~/work/Console$
在使用 gedit 编辑 make.rsp 时,添加如下前四行的内容:
01: -t:library 02: -out:Console.dll 03: -unsafe 04: -nowarn:436 05: mcs/build/common/Locale.cs 06: mcs/build/common/MonoTODOAttribute.cs 07: mcs/class/corlib/System/Buffer.cs 08: mcs/class/corlib/System/ConsoleCancelEventArgs.cs 09: mcs/class/corlib/System/ConsoleCancelEventHandler.cs 10: mcs/class/corlib/System/Console.cs 11: mcs/class/corlib/System/ConsoleDriver.cs 12: mcs/class/corlib/System/ConsoleKeyInfo.cs 13: mcs/class/corlib/System/ControlCharacters.cs 14: mcs/class/corlib/System/CStreamReader.cs 15: mcs/class/corlib/System/CStreamWriter.cs 16: mcs/class/corlib/System/IConsoleDriver.cs 17: mcs/class/corlib/System.IO/NullStream.cs 18: mcs/class/corlib/System.IO/UnexceptionalStreamReader.cs 19: mcs/class/corlib/System.IO/UnexceptionalStreamWriter.cs 20: mcs/class/corlib/System/KnownTerminals.cs 21: mcs/class/corlib/System/NullConsoleDriver.cs 22: mcs/class/corlib/System/TermInfoBooleans.cs 23: mcs/class/corlib/System/TermInfoDriver.cs 24: mcs/class/corlib/System/TermInfoNumbers.cs 25: mcs/class/corlib/System/TermInfoReader.cs 26: mcs/class/corlib/System/TermInfoStrings.cs 27: mcs/class/corlib/System/WindowsConsoleDriver.cs 28: Skyiv/AssemblyInfo.cs 29: Skyiv/Environment.cs 30: Skyiv/ExtensionMethods.cs 31: Skyiv/MonoIO.cs 32: Skyiv/Stub.cs
终于,我们成功地使用 C# 编译器编译生成了 Console.dll 程序集文件。当然,这个 Console.dll 仅仅是用来研究 Mono 的源代码,是不能正常工作的,因为我们使用了一些自己编写的辅助代码替代了 Mono 系统的。
查看源程序的目录结构
下面就是我们工作目录的内容:
各种类型之间的关系图
在上图中,最核心的类型如下所示:
- Console: public static class,调用下面的 ConsoleDriver 类的静态方法和静态属性来干活。
- ConsoleDriver: internal class,内部持有一个类型为 IConsoleDriver 接口的 internal 静态字段。
- IConsoleDriver: internal interface,以下三个类均实现 IConsoleDriver 接口。
- NullConsoleDriver: internal class,只实现最基本的控制台输入/输出功能,用于哑终端等情况。
- TermInfoDriver: internal class,用于 Unix 操作系统的各种终端。
- WindowsConsoleDriver: internal class,用于 Windows 操作系统的控制台。
可以点击下载 Console.7z。
相关推荐
标题中的“mod_mono源代码 与 Win32下....他们可以通过分析源代码学习mod_mono的工作机制,或者根据提供的预编译文件快速部署服务。同时,对于希望了解.NET/Mono如何与Apache集成的人来说,这也是一个很好的学习材料。
【Mono for Android学习笔记全套】是一份详尽的资源,旨在帮助开发者掌握使用Mono和C#进行Android应用开发的技术。Mono是.NET框架的一个开源实现,它使得C#开发者能够在多种平台上,包括Android,编写和运行应用程序...
《深入探索:.NET开源框架Mono的源代码分析——聚焦pnetlib-0.7.4》 在软件开发领域,源代码分析是一项至关重要的任务,它有助于我们理解底层实现,提升编程技能,并且能够为自定义扩展或优化提供宝贵参考。当我们...
标题中的“VINS-Mono代码注释”意味着这是一个包含了VINS-Mono源代码及其详细解释的学习资源。这样的资料对于深入理解VINS-Mono的工作原理和算法细节至关重要。通过阅读和分析代码注释,SLAM算法工程师可以了解到...
VINS-Mono源代码流程框图——feature_tracker部分,高清PDF版本。可对照此流程框图帮助理解和梳理代码整体逻辑,可参考文章:https://blog.csdn.net/weixin_50578602/article/details/127788385,适合于刚入坑SLAM的...
在docker的mono镜像中加入一些基本命令包,方便开发(公司内网有些不能下)。有需求的直接下载,同时不需要再到仓库龟速下载了。送上安装命令: docker load -i mono.tar
这套学习笔记全面覆盖了这两个平台的基础知识、核心概念以及高级特性,对于想要深入理解和掌握Mono在Android开发中的应用非常有价值。 首先,我们来了解一下Mono for Android。它是一个.NET开发环境,允许开发者...
这个"mono for android官方示例程序"是官方提供的一系列示例代码,旨在帮助开发者更好地理解和学习如何在Android平台上使用Mono进行应用程序开发。 1. ** Mono 框架**:Mono是一个开源的.NET实现,由Miguel de ...
标题中的"C#注入器源代码.rar 可以注入Unity mono"指的是一个利用C#编程语言编写的工具,其主要功能是能够对Unity引擎中的Mono运行时环境进行代码注入。在游戏开发领域,尤其是Unity游戏,Mono是用于执行C#脚本的...
可以选择从源代码构建和安装Mono Framework。 要求 平台: Debian 7.8 Ubuntu 14.04 CentOS的7.0 红帽等 以下食谱是依赖项: 易于 百胜 百胜 吉特 必要的 菜谱 默认值-您要在运行列表中使用的配方。 用法 只需...
这个压缩包"VINS-Mono代码注释.7z"包含了VINS-Mono算法的源代码以及相关的注释,对于理解和实现这类技术非常有帮助。 首先,VINS-Mono的核心在于融合视觉信息(来自摄像头)和惯性信息(来自IMU),以实现高精度的...
mono for android sqlite操作示例源代码、 包括 sqliteconnection 获取 地址设置 commond 链接,操作 完成了 数据库文件创建,数据库表创建, 内容添加等 没做提示窗口, 请用 Android device logging 查找标签:...
在移动应用开发中,尤其是使用跨平台框架如Xamarin或Unity时,`Mono`是一个重要的组件,它提供了.NET Framework在不同操作系统上的运行环境。在这些框架下,开发者可以使用C#语言编写代码,实现与原生平台类似的交互...
VINS-Mono代码注释以及公式推导
通过共享代码库,开发者可以编写一次代码,然后在多个平台上运行,极大地提高了开发效率和代码复用性。 2. **原生应用体验**:尽管是跨平台开发,但Xamarin生成的是与原生平台API交互的本地应用程序,这意味着用户...
VINS-Mono是一种基于单目视觉的即时定位与建图...通过理解和学习VINS-Mono的代码,可以深入了解SLAM算法,尤其是视觉惯性融合方面的技术,这对于从事机器人导航、自动驾驶或无人机领域的研究人员和工程师来说极其宝贵。
<plugin> <groupId>com.threerings.maven</groupId> <artifactId>mono-maven-plugin</artifactId> <version>0.0-SNAPSHOT</version></plugin>有关所有选项的完整说明,请查看源代码或 maven 帮助: mvn help:...
"mod-mono-master" 是一个与 Mono 开源项目相关的压缩包,主要包含的是 Mono 的 mod_mono 模块的源代码。Mono 是一个跨平台的开源软件开发环境,它实现了 .NET Framework 的大部分功能,允许开发者在 Linux、macOS、...
除了基本的运行环境,"mod_mono-master"这个文件可能是Mod_mono的源代码。Mod_mono是一个Apache HTTP服务器模块,它允许在Apache服务器上运行ASP.NET应用。它将.NET应用程序与流行的Web服务器集成,提供了更高的性能...