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


    NullStream 类 (internal class)

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

    01:  namespace System.IO
    02:  {
    03:    class NullStream : Stream
    04:    {
    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.IO
    02:  {
    03:    partial class Stream
    04:    {
    05:      private sealed class NullStream : Stream
    06:      {
    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.IO
    02:  {
    03:    [Serializable]
    04:    [ComVisible(true)]
    05:    public abstract partial class Stream : MarshalByRefObject, IDisposable
    06:    {
    07:      public static readonly Stream Null = new NullStream();
    08:  
    09:      //
    10:      // 这里省略 Stream 类的其余成员
    11:      //
    12:    }
    13:  }

    如上述源程序第 5 行所看到的。加上 partial keyword即可了。

    第 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.cs
    003:  //
    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.com
    011:  // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
    012:  //
    013:  // Permission is hereby granted, free of charge, to any person obtaining
    014:  // a copy of this software and associated documentation files (the
    015:  // "Software"), to deal in the Software without restriction, including
    016:  // without limitation the rights to use, copy, modify, merge, publish,
    017:  // distribute, sublicense, and/or sell copies of the Software, and to
    018:  // permit persons to whom the Software is furnished to do so, subject to
    019:  // the following conditions:
    020:  // 
    021:  // The above copyright notice and this permission notice shall be
    022:  // 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 OF
    026:  // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    027:  // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
    028:  // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    029:  // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
    030:  // 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 that
    035:  // catches IOException so that graphical applications don't suddenly
    036:  // get IO errors when their terminal vanishes.  See
    037:  // 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 overflow
    135:              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 操作系统中就是如此。其值为” ”,而在 Unix 操作系统中其值为” ”)推断是否遇到了行结束符。即 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.cs
    003:  //
    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.com
    010:  //
    011:  
    012:  //
    013:  // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
    014:  //
    015:  // Permission is hereby granted, free of charge, to any person obtaining
    016:  // a copy of this software and associated documentation files (the
    017:  // "Software"), to deal in the Software without restriction, including
    018:  // without limitation the rights to use, copy, modify, merge, publish,
    019:  // distribute, sublicense, and/or sell copies of the Software, and to
    020:  // permit persons to whom the Software is furnished to do so, subject to
    021:  // the following conditions:
    022:  // 
    023:  // The above copyright notice and this permission notice shall be
    024:  // 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 OF
    028:  // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    029:  // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
    030:  // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    031:  // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
    032:  // 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 that
    037:  // catches IOException so that graphical applications don't suddenly
    038:  // get IO errors when their terminal vanishes (ie when they spew debug
    039:  // 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 中被使用过两次。

  • 相关阅读:
    基于vue-cli配置移动端自适应项目
    webpack 之 resolve.alias(别名)
    vue 之引用全局样式
    webpack 3.0
    vue 之 data为什么必须声明为返回一个初始数据对象的函数?
    JS柯里化
    《css设计指南》 读书笔记 二
    《css设计指南》 读书笔记 一
    简单的移动端图片预览 包含放大缩小以及对各种手势的判定
    图片拍照上传 使用fileReader 无需跨域
  • 原文地址:https://www.cnblogs.com/wzjhoutai/p/7007971.html
Copyright © 2020-2023  润新知