`
backspace
  • 浏览: 137104 次
文章分类
社区版块
存档分类
最新评论

Mono源代码学习笔记:Console类(一)

 
阅读更多

前言

我们知道,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 文件中,包含以下三个类:

  1. public abstract class Stream : MarshalByRefObject, IDisposable
  2. internal class NullStream : Stream
  3. 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 系统的。

查看源程序的目录结构

下面就是我们工作目录的内容:

Console02

各种类型之间的关系图

Console01

在上图中,最核心的类型如下所示:

  1. Console: public static class,调用下面的 ConsoleDriver 类的静态方法和静态属性来干活。
  2. ConsoleDriver: internal class,内部持有一个类型为 IConsoleDriver 接口的 internal 静态字段。
  3. IConsoleDriver: internal interface,以下三个类均实现 IConsoleDriver 接口。
  4. NullConsoleDriver: internal class,只实现最基本的控制台输入/输出功能,用于哑终端等情况。
  5. TermInfoDriver: internal class,用于 Unix 操作系统的各种终端。
  6. WindowsConsoleDriver: internal class,用于 Windows 操作系统的控制台。

可以点击下载 Console.7z

1
1
分享到:
评论

相关推荐

    mod_mono源代码 与 Win32下.so文件

    标题中的“mod_mono源代码 与 Win32下....他们可以通过分析源代码学习mod_mono的工作机制,或者根据提供的预编译文件快速部署服务。同时,对于希望了解.NET/Mono如何与Apache集成的人来说,这也是一个很好的学习材料。

    MONO FOR ANDROID学习笔记全套

    【Mono for Android学习笔记全套】是一份详尽的资源,旨在帮助开发者掌握使用Mono和C#进行Android应用开发的技术。Mono是.NET框架的一个开源实现,它使得C#开发者能够在多种平台上,包括Android,编写和运行应用程序...

    .net 开源框架Mono 源代码 pnetlib-0.7.4.tar

    《深入探索:.NET开源框架Mono的源代码分析——聚焦pnetlib-0.7.4》 在软件开发领域,源代码分析是一项至关重要的任务,它有助于我们理解底层实现,提升编程技能,并且能够为自定义扩展或优化提供宝贵参考。当我们...

    VINS-Mono代码注释,仅供学习

    标题中的“VINS-Mono代码注释”意味着这是一个包含了VINS-Mono源代码及其详细解释的学习资源。这样的资料对于深入理解VINS-Mono的工作原理和算法细节至关重要。通过阅读和分析代码注释,SLAM算法工程师可以了解到...

    VINS-Mono源代码详细流程框图(1)-feature-tracker部分

    VINS-Mono源代码流程框图——feature_tracker部分,高清PDF版本。可对照此流程框图帮助理解和梳理代码整体逻辑,可参考文章:https://blog.csdn.net/weixin_50578602/article/details/127788385,适合于刚入坑SLAM的...

    docker的mono镜像

    在docker的mono镜像中加入一些基本命令包,方便开发(公司内网有些不能下)。有需求的直接下载,同时不需要再到仓库龟速下载了。送上安装命令: docker load -i mono.tar

    Mono for Android和MonoDroid学习笔记全套

    这套学习笔记全面覆盖了这两个平台的基础知识、核心概念以及高级特性,对于想要深入理解和掌握Mono在Android开发中的应用非常有价值。 首先,我们来了解一下Mono for Android。它是一个.NET开发环境,允许开发者...

    mono for android官方示例程序

    这个"mono for android官方示例程序"是官方提供的一系列示例代码,旨在帮助开发者更好地理解和学习如何在Android平台上使用Mono进行应用程序开发。 1. ** Mono 框架**:Mono是一个开源的.NET实现,由Miguel de ...

    C#注入器源代码.rar 可以注入Unity mono

    标题中的"C#注入器源代码.rar 可以注入Unity mono"指的是一个利用C#编程语言编写的工具,其主要功能是能够对Unity引擎中的Mono运行时环境进行代码注入。在游戏开发领域,尤其是Unity游戏,Mono是用于执行C#脚本的...

    mono4-coobook:从软件包和源代码安装和配置Mono v4 Framework

    可以选择从源代码构建和安装Mono Framework。 要求 平台: Debian 7.8 Ubuntu 14.04 CentOS的7.0 红帽等 以下食谱是依赖项: 易于 百胜 百胜 吉特 必要的 菜谱 默认值-您要在运行列表中使用的配方。 用法 只需...

    VINS-Mono代码注释.7z

    这个压缩包"VINS-Mono代码注释.7z"包含了VINS-Mono算法的源代码以及相关的注释,对于理解和实现这类技术非常有帮助。 首先,VINS-Mono的核心在于融合视觉信息(来自摄像头)和惯性信息(来自IMU),以实现高精度的...

    mono for android sqlite操作示例源代码

    mono for android sqlite操作示例源代码、 包括 sqliteconnection 获取 地址设置 commond 链接,操作 完成了 数据库文件创建,数据库表创建, 内容添加等 没做提示窗口, 请用 Android device logging 查找标签:...

    Mono 代码实现系统返回,跳转至上一页面

    在移动应用开发中,尤其是使用跨平台框架如Xamarin或Unity时,`Mono`是一个重要的组件,它提供了.NET Framework在不同操作系统上的运行环境。在这些框架下,开发者可以使用C#语言编写代码,实现与原生平台类似的交互...

    VINS-Mono代码注释以及公式推导

    VINS-Mono代码注释以及公式推导

    Xamarin学习笔记&案例

    通过共享代码库,开发者可以编写一次代码,然后在多个平台上运行,极大地提高了开发效率和代码复用性。 2. **原生应用体验**:尽管是跨平台开发,但Xamarin生成的是与原生平台API交互的本地应用程序,这意味着用户...

    VINS-Mono代码详细注释

    VINS-Mono是一种基于单目视觉的即时定位与建图...通过理解和学习VINS-Mono的代码,可以深入了解SLAM算法,尤其是视觉惯性融合方面的技术,这对于从事机器人导航、自动驾驶或无人机领域的研究人员和工程师来说极其宝贵。

    mono-maven-plugin:待定

    <plugin> <groupId>com.threerings.maven</groupId> <artifactId>mono-maven-plugin</artifactId> <version>0.0-SNAPSHOT</version></plugin>有关所有选项的完整说明,请查看源代码或 maven 帮助: mvn help:...

    mod-mono-master

    "mod-mono-master" 是一个与 Mono 开源项目相关的压缩包,主要包含的是 Mono 的 mod_mono 模块的源代码。Mono 是一个跨平台的开源软件开发环境,它实现了 .NET Framework 的大部分功能,允许开发者在 Linux、macOS、...

    mono开发包

    除了基本的运行环境,"mod_mono-master"这个文件可能是Mod_mono的源代码。Mod_mono是一个Apache HTTP服务器模块,它允许在Apache服务器上运行ASP.NET应用。它将.NET应用程序与流行的Web服务器集成,提供了更高的性能...

Global site tag (gtag.js) - Google Analytics