我是靠谱客的博主 个性冥王星,这篇文章主要介绍Mono源代码学习笔记:Console类(四),现在分享给大家,希望可以做个参考。

NullStream 类 (internal class)

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

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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 类的这两个虚方法的代码:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
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 改为如下所示:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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 只需作如下改动:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
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 关键字就行了。

第 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:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
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 操作系统中就是如此,其值为”rn”,而在 Unix 操作系统中其值为”n”)判断是否遇到了行结束符,即 EOL,也就是 Environment.NewLine。

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

UnexceptionalStreamWriter 类 (internal class)

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

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
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 中被使用过两次。

 

(未完待续)

最后

以上就是个性冥王星最近收集整理的关于Mono源代码学习笔记:Console类(四)的全部内容,更多相关Mono源代码学习笔记内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(50)

评论列表共有 0 条评论

立即
投稿
返回
顶部