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

来源:互联网 发布:中国数据库市场规模 编辑:程序博客网 时间:2024/05/16 05:30

NullStream 类 (internal class)

下面就是 mcs/class/corlib/System.IO/NullStream.cs:

01:  namespace System.IO02:  {03:    class NullStream : Stream04:    {05:      public override bool CanRead { get { return true; } }06:      public override bool CanSeek { get { return true; } }07:      public override bool CanWrite { get { return true; } }08:      public override long Length { get { return 0; } }09:      public override long Position { get { return 0; } set { } }10:      public override void Flush() { }11:      public override int Read(byte[] buffer, int offset, int count) { return 0; }12:      public override int ReadByte() { return -1; }13:      public override long Seek(long offset, SeekOrigin origin) { return 0; }14:      public override void SetLength(long value) { }15:      public override void Write(byte[] buffer, int offset, int count) { }16:      public override void WriteByte(byte value) { }17:    }18:  }

上述源程序定义了 NullStream 类。我在我个系列学习笔记第一篇中谈到,这个 NullStream 类是从 Stream.cs 中分离出来的,经过我的整理后就变成上面这个样子。从上述的源程序中可以看出:

  1. NullStream 类位于 System.IO 命名空间中。(第 1 行)
  2. NullStream 继承自抽象基类 Stream。(第 3 行)
  3. NullStream 是个 internal 类,只能用在本程序集中。(第 3 行)
  4. NullStream 有 12 个成员,全部是公共成员,用于重写抽象基类 Stream 的虚成员。(5 - 16 行)
  5. NullStream 有 5 个属性。这些属性的 get 方法仅返回零或者 true,仅有的一个 set 方法是空的。(5 - 9行)
  6. NullStream 有 7 个方法,这方法要么是空的,要么仅返回零或者 -1。(10 – 16 行)

NullStream 类实践了 Null Object 设计模式。

由于 NullStream 类是作为 Null Object 使用的,它可以不重写抽象基类 Stream 的 ReadByte 方法(第 12 行)和 WriteByte 方法(第 16 行),因为 Stream 的这两个方法都是虚(virtual)方法,而不是抽象(abstract)方法。下面就是 Mono 源代码中的 mcs/class/corlib/System.IO/Stream.cs 文件中 Stream 类的这两个虚方法的代码:

01:  public virtual int ReadByte()02:  {03:    byte[] buffer = new byte[1];04:    if (Read(buffer, 0, 1) == 1) return buffer[0];05:    return -1;06:  }07:  08:  public virtual void WriteByte(byte value)09:  {10:    byte[] buffer = new byte[1];11:    buffer[0] = value;12:    Write(buffer, 0, 1);13:  }

可以看出,Stream 类的 ReadByte 方法创建一个新的单字节数组,然后调用 Read 方法(第 3 行到第 5 行)。Stream 类的 WriteByte 方法创建一个新的单字节数组,然后调用 Write 方法(第 10 行到第 12 行)。也就是说,如果 NullStream 类不重写抽象基类 Stream 的 ReadByte 方法和 WriteByte 方法,得到的运行结果也是一样的。但是,这样效率就低了很多。

在 Console.dll 项目中,NullStream 类仅在 Console.cs 中被使用过一次。

对 NullStream 类的改进建议

我建议将 mcs/class/corlib/System.IO/NullStream.cs 改为如下所示:

01:  namespace System.IO02:  {03:    partial class Stream04:    {05:      private sealed class NullStream : Stream06:      {07:        public override bool CanRead { get { return true; } }08:        public override bool CanSeek { get { return true; } }09:        public override bool CanWrite { get { return true; } }10:        public override long Length { get { return 0; } }11:        public override long Position { get { return 0; } set { } }12:        public override void Flush() { }13:        public override int Read(byte[] buffer, int offset, int count) { return 0; }14:        public override int ReadByte() { return -1; }15:        public override long Seek(long offset, SeekOrigin origin) { return 0; }16:        public override void SetLength(long value) { }17:        public override void Write(byte[] buffer, int offset, int count) { }18:        public override void WriteByte(byte value) { }19:      }20:    }21:  }

也就是说,将 NullStream 类从 System.IO 命名空间中的 internal 类更改为 System.IO.Stream 类的私有(private)密封(sealed)内嵌类(请参阅上述源程序第 5 行)。而 mcs/class/corlib/System.IO/Stream.cs 只需作如下改动:

01:  namespace System.IO02:  {03:    [Serializable]04:    [ComVisible(true)]05:    public abstract partial class Stream : MarshalByRefObject, IDisposable06:    {07:      public static readonly Stream Null = new NullStream();08:  09:      //10:      // 这里省略 Stream 类的其余成员11:      //12:    }13:  }

如上述源程序第 5 行所示,加上 partial 关键字就行了。

第 7 行通过 Stream 类的 Null 公共只读静态字段对外公开了 NullStream 类。注意,这是 Stream.cs 中原来的代码,我没有作任何改动。

现在,其他程序要使用 NullStream 类,只有通过 Stream.Null 字段来使用了,这也是 NullStream 类的唯一实例。在我们的 Console.cs 中,原来是通过 new NullStream() 来使用 NullStream 类的,现在需要改为 Stream.Null 了。

这样做的好处是显而易见的:

  1. 我们对外隐藏了 NullStream 类,大家只需要知道 Stream.Null 这个公共只读静态字段好了。
  2. NullStream 类只被实例化一次,提高了效率。
  3. NullStream 类被声明为 sealed 的,可能对 C# 编译器以及 JIT 优化调用该类的虚方法的语句有好处。例如,有可能使用 call 指令代替 callvirt 指令。

这也实践了 Singleton 设计模式和 Null Object 设计模式。

UnexceptionalStreamReader 类 (internal class)

下面就是 mcs/class/corlib/System.IO/UnexceptionalStreamReader.cs:

001:  //002:  // System.IO.UnexceptionalStreamReader.cs003:  //004:  // Authors:005:  //   Dietmar Maurer (dietmar@ximian.com)006:  //   Miguel de Icaza (miguel@ximian.com)007:  //   Dick Porter (dick@ximian.com)008:  //   Sebastien Pouliot  <sebastien@ximian.com>009:  //010:  // (C) Ximian, Inc.  http://www.ximian.com011:  // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)012:  //013:  // Permission is hereby granted, free of charge, to any person obtaining014:  // a copy of this software and associated documentation files (the015:  // "Software"), to deal in the Software without restriction, including016:  // without limitation the rights to use, copy, modify, merge, publish,017:  // distribute, sublicense, and/or sell copies of the Software, and to018:  // permit persons to whom the Software is furnished to do so, subject to019:  // the following conditions:020:  // 021:  // The above copyright notice and this permission notice shall be022:  // included in all copies or substantial portions of the Software.023:  // 024:  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,025:  // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF026:  // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND027:  // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE028:  // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION029:  // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION030:  // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.031:  //032:  033:  034:  // This is a wrapper around StreamReader used by System.Console that035:  // catches IOException so that graphical applications don't suddenly036:  // get IO errors when their terminal vanishes.  See037:  // UnexceptionalStreamWriter too.038:  039:  using System.Text;040:  using System.Runtime.InteropServices;041:  042:  namespace System.IO {043:      internal class UnexceptionalStreamReader : StreamReader {044:  045:          private static bool[] newline = new bool [Environment.NewLine.Length];046:  047:          private static char newlineChar;048:  049:          static UnexceptionalStreamReader () {050:              string n = Environment.NewLine;051:              if (n.Length == 1)052:                  newlineChar = n [0];053:          }054:  055:          public UnexceptionalStreamReader(Stream stream)056:              : base (stream)057:          {058:          }059:  060:          public UnexceptionalStreamReader(Stream stream, bool detect_encoding_from_bytemarks)061:              : base (stream, detect_encoding_from_bytemarks)062:          {063:          }064:  065:          public UnexceptionalStreamReader(Stream stream, Encoding encoding)066:              : base (stream, encoding)067:          {068:          }069:  070:          public UnexceptionalStreamReader(Stream stream, Encoding encoding, bool detect_encoding_from_bytemarks)071:              : base (stream, encoding, detect_encoding_from_bytemarks)072:          {073:          }074:          075:          public UnexceptionalStreamReader(Stream stream, Encoding encoding, bool detect_encoding_from_bytemarks, int buffer_size)076:              : base (stream, encoding, detect_encoding_from_bytemarks, buffer_size)077:          {078:          }079:  080:          public UnexceptionalStreamReader(string path)081:              : base (path)082:          {083:          }084:  085:          public UnexceptionalStreamReader(string path, bool detect_encoding_from_bytemarks)086:              : base (path, detect_encoding_from_bytemarks)087:          {088:          }089:  090:          public UnexceptionalStreamReader(string path, Encoding encoding)091:              : base (path, encoding)092:          {093:          }094:  095:          public UnexceptionalStreamReader(string path, Encoding encoding, bool detect_encoding_from_bytemarks)096:              : base (path, encoding, detect_encoding_from_bytemarks)097:          {098:          }099:          100:          public UnexceptionalStreamReader(string path, Encoding encoding, bool detect_encoding_from_bytemarks, int buffer_size)101:              : base (path, encoding, detect_encoding_from_bytemarks, buffer_size)102:          {103:          }104:  105:          public override int Peek ()106:          {107:              try {108:                  return(base.Peek ());109:              } catch (IOException) {110:              }111:  112:              return(-1);113:          }114:  115:          public override int Read ()116:          {117:              try {118:                  return(base.Read ());119:              } catch (IOException) {120:              }121:  122:              return(-1);123:          }124:  125:          public override int Read ([In, Out] char[] dest_buffer,126:                        int index, int count)127:          {128:              if (dest_buffer == null)129:                  throw new ArgumentNullException ("dest_buffer");130:              if (index < 0)131:                  throw new ArgumentOutOfRangeException ("index", "< 0");132:              if (count < 0)133:                  throw new ArgumentOutOfRangeException ("count", "< 0");134:              // ordered to avoid possible integer overflow135:              if (index > dest_buffer.Length - count)136:                  throw new ArgumentException ("index + count > dest_buffer.Length");137:  138:              int chars_read = 0;139:              char nl = newlineChar;140:              try {141:                  while (count > 0) {142:                      int c = base.Read ();143:                      if (c < 0)144:                          break;145:                      chars_read++;146:                      count--;147:  148:                      dest_buffer [index] = (char) c;149:                      // shortcut when a new line is only one character (e.g. Linux, Mac)150:                      if (nl != (char)0) {151:                          if ((char)c == nl)152:                              return chars_read;153:                      } else {154:                          if (CheckEOL ((char)c))155:                              return chars_read;156:                      }157:                      index ++;158:                  }159:              } catch (IOException) {160:              }161:              162:              return chars_read;163:          }164:  165:          private bool CheckEOL (char current)166:          {167:              // general case for any length (e.g. Windows)168:              for (int i=0; i < newline.Length; i++) {169:                  if (!newline [i]) {170:                      if (current == Environment.NewLine [i]) {171:                          newline [i] = true;172:                          return (i == newline.Length - 1);173:                      }174:                      break;175:                  }176:              }177:              for (int j=0; j < newline.Length; j++)178:                  newline [j] = false;179:              return false;180:          }181:  182:          public override string ReadLine()183:          {184:              try {185:                  return(base.ReadLine ());186:              } catch (IOException) {187:              }188:  189:              return(null);190:          }191:  192:          public override string ReadToEnd()193:          {194:              try {195:                  return(base.ReadToEnd ());196:              } catch (IOException) {197:              }198:  199:              return(null);200:          }201:      }202:  }

上述源程序定义了 UnexceptionalStreamReader 类。该类位于 System.IO 命名空间中,继承自 StreamReader 类,是 internal 的,即只能在本程序集中使用。

UnexceptionalStreamReader 类是对 StreamReader 类的包装,捕获并忽略所有的 IOException 异常。它用于 Console 类中,以免 IO 错误干扰控制台的正常运行。

UnexceptionalStreamReader 类定义了以下两个私有静态字段:

  1. newline: private static,类型为 bool[]。(第 45 行)
  2. newlineChar: private static,类型为 char。(第 47 行)

第 49 行到第 53 行的静态构造函数对 newlineChar 字段有条件地赋值。

第 55 行到第 103 行的十个构造函数仅是调用基类 StreamReader 相应的构造函数而已。

第 105 行到第 123 行以及第 182 行到第 200 行的四个方法重写了基类 StreamReader 中相应的虚方法,简单地调用基类中相应的虚方法,捕获并忽略 IOException 异常。

第 125 行到第 163 行的 Read 方法也是重写了基类的虚方法,但是它没有简单地调用基类中相应的虚方法。它首先检查输入的参数是否合法,然后在循环中调用基类的另一个 Read 方法一个个地读取字符,捕获并忽略 IOException 异常。注意这个 Read 方法的语义不同于其基类 StreamReader 中相应的 Read 方法的语义,前者遇到 EOL 就提前返回,而后者要遇到 EOF 才会提前返回。

第 165 行到第 180 行的 CheckEOL 方法是私有(private)方法,仅在第 154 行被调用过,用于在 Environment.NewLine 不止一个字符时(在 Windows 操作系统中就是如此,其值为”\r\n”,而在 Unix 操作系统中其值为”\n”)判断是否遇到了行结束符,即 EOL,也就是 Environment.NewLine。

在 Console.dll 项目中,UnexceptionalStreamReader 类在 Console.cs 中被使用过一次。在上述源程序的第 34 行到第 37 行的注释中也已经指出了这一点。

UnexceptionalStreamWriter 类 (internal class)

下面就是 mcs/class/corlib/System.IO/UnexceptionalStreamWriter.cs:

001:  //002:  // System.IO.StreamWriter.cs003:  //004:  // Authors:005:  //   Dietmar Maurer (dietmar@ximian.com)006:  //   Paolo Molaro (lupus@ximian.com)007:  //   Dick Porter (dick@ximian.com)008:  //009:  // (C) Ximian, Inc.  http://www.ximian.com010:  //011:  012:  //013:  // Copyright (C) 2004 Novell, Inc (http://www.novell.com)014:  //015:  // Permission is hereby granted, free of charge, to any person obtaining016:  // a copy of this software and associated documentation files (the017:  // "Software"), to deal in the Software without restriction, including018:  // without limitation the rights to use, copy, modify, merge, publish,019:  // distribute, sublicense, and/or sell copies of the Software, and to020:  // permit persons to whom the Software is furnished to do so, subject to021:  // the following conditions:022:  // 023:  // The above copyright notice and this permission notice shall be024:  // included in all copies or substantial portions of the Software.025:  // 026:  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,027:  // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF028:  // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND029:  // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE030:  // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION031:  // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION032:  // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.033:  //034:  035:  036:  // This is a wrapper around StreamWriter used by System.Console that037:  // catches IOException so that graphical applications don't suddenly038:  // get IO errors when their terminal vanishes (ie when they spew debug039:  // output.)  See UnexceptionalStreamReader too.040:  041:  using System.Text;042:  using System;043:  044:  namespace System.IO {045:      internal class UnexceptionalStreamWriter: StreamWriter {046:          public UnexceptionalStreamWriter (Stream stream)047:              : base (stream)048:          {049:          }050:  051:          public UnexceptionalStreamWriter (Stream stream,052:                            Encoding encoding)053:              : base (stream, encoding)054:          {055:          }056:  057:          public UnexceptionalStreamWriter (Stream stream,058:                            Encoding encoding,059:                            int bufferSize)060:              : base (stream, encoding, bufferSize)061:          {062:          }063:  064:          public UnexceptionalStreamWriter (string path)065:              : base (path)066:          {067:          }068:  069:          public UnexceptionalStreamWriter (string path, bool append)070:              : base (path, append)071:          {072:          }073:  074:          public UnexceptionalStreamWriter (string path, bool append,075:                            Encoding encoding)076:              : base (path, append, encoding)077:          {078:          }079:  080:          public UnexceptionalStreamWriter (string path, bool append,081:                            Encoding encoding,082:                            int bufferSize)083:              : base (path, append, encoding, bufferSize)084:          {085:          }086:  087:          public override void Flush ()088:          {089:              try {090:                  base.Flush ();091:              } catch (Exception) {092:              }093:          }094:  095:          public override void Write (char[] buffer, int index,096:                          int count)097:          {098:              try {099:                  base.Write (buffer, index, count);100:              } catch (IOException) {101:              }102:          }103:  104:          public override void Write (char value)105:          {106:              try {107:                  base.Write (value);108:              } catch (IOException) {109:              }110:          }111:  112:          public override void Write (char[] value)113:          {114:              try {115:                  base.Write (value);116:              } catch (IOException) {117:              }118:          }119:  120:          public override void Write (string value)121:          {122:              try {123:                  base.Write (value);124:              } catch (IOException) {125:              }126:          }127:      }128:  }

上述源程序定义了 UnexceptionStreamWriter 类。该类位于 System.IO 命名空间中,继承自 StreamWriter 类,是 internal 的,即只能在本程序集中使用。

第 2 行的注释“System.IO.StreamWriter.cs”有误,应改为“System.IO.UnexceptionStreamWriter”。

UnexceptionalStreamWriter 类是对 StreamWriter 类的包装,捕获并忽略所有的 IOException 异常。它用于 Console 类中,以免 IO 错误干扰控制台的正常运行。

第 46 行到第 85 行的七个构造函数仅是调用基类 StreamWriter 相应的构造函数而已。

第 87 行到第 126 行的五个方法重写了基类 StreamWriter 中相应的虚方法,简单地调用基类中相应的虚方法,捕获并忽略 IOException 异常。

在 Console.dll 项目中,UnexceptionStreamWriter 类在 Console.cs 中被使用过两次。

0 0
原创粉丝点击