Mono源码学习笔记:Console类(四)
NullStream 類(lèi) (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 類(lèi)。我在我個(gè)系列學(xué)習(xí)筆記第一篇中談到。這個(gè) NullStream 類(lèi)是從 Stream.cs 中分離出來(lái)的,經(jīng)過(guò)我的整理后就變成上面這個(gè)樣子。從上述的源程序中能夠看出:
(第 1 行)
(5 - 16 行)
這些屬性的 get 方法僅返回零或者 true,僅有的一個(gè) set 方法是空的。(5 - 9行)
NullStream 類(lèi)實(shí)踐了 Null Object 設(shè)計(jì)模式。
因?yàn)?NullStream 類(lèi)是作為 Null Object 使用的,它能夠不重寫(xiě)抽象基類(lèi) Stream 的?ReadByte?方法(第 12 行)和?WriteByte?方法(第 16 行),由于 Stream 的這兩個(gè)方法都是虛(virtual)方法,而不是抽象(abstract)方法。
以下就是 Mono 源碼中的 mcs/class/corlib/System.IO/Stream.cs 文件里 Stream 類(lèi)的這兩個(gè)虛方法的代碼:
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 類(lèi)的 ReadByte 方法創(chuàng)建一個(gè)新的單字節(jié)數(shù)組,然后調(diào)用 Read 方法(第 3 行到第 5 行)。Stream 類(lèi)的 WriteByte 方法創(chuàng)建一個(gè)新的單字節(jié)數(shù)組,然后調(diào)用 Write 方法(第 10 行到第 12 行)。也就是說(shuō),假設(shè) NullStream 類(lèi)不重寫(xiě)抽象基類(lèi) Stream 的 ReadByte 方法和 WriteByte 方法。得到的執(zhí)行結(jié)果也是一樣的。
可是。這樣效率就低了非常多。
在 Console.dll 項(xiàng)目中,NullStream 類(lèi)僅在 Console.cs 中被使用過(guò)一次。
對(duì) NullStream 類(lèi)的改進(jìn)建議
我建議將 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: }也就是說(shuō),將 NullStream 類(lèi)從 System.IO 命名空間中的 internal 類(lèi)更改為 System.IO.Stream 類(lèi)的私有(private)密封(sealed)內(nèi)嵌類(lèi)(請(qǐng)參閱上述源程序第 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 類(lèi)的其余成員 11: // 12: } 13: }如上述源程序第 5 行所看到的。加上 partial keyword即可了。
第 7 行通過(guò) Stream 類(lèi)的?Null?公共僅僅讀靜態(tài)字段對(duì)外公開(kāi)了 NullStream 類(lèi)。
注意。這是 Stream.cs 中原來(lái)的代碼。我沒(méi)有作不論什么修改。
如今。其它程序要使用 NullStream 類(lèi)。僅僅有通過(guò) Stream.Null?字段來(lái)使用了,這也是 NullStream 類(lèi)的唯一實(shí)例。在我們的 Console.cs 中。原來(lái)是通過(guò) new NullStream() 來(lái)使用 NullStream 類(lèi)的,如今須要改為 Stream.Null?了。
這樣做的優(yōu)點(diǎn)是顯而易見(jiàn)的:
比如,有可能使用 call 指令取代 callvirt 指令。
這也實(shí)踐了 Singleton 設(shè)計(jì)模式和 Null Object 設(shè)計(jì)模式。
UnexceptionalStreamReader 類(lèi) (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 類(lèi)。該類(lèi)位于 System.IO 命名空間中,繼承自 StreamReader 類(lèi)。是 internal 的。即僅僅能在本程序集中使用。
UnexceptionalStreamReader 類(lèi)是對(duì) StreamReader 類(lèi)的包裝,捕獲并忽略全部的 IOException 異常。它用于 Console 類(lèi)中,以免 IO 錯(cuò)誤干擾控制臺(tái)的正常執(zhí)行。
UnexceptionalStreamReader 類(lèi)定義了下面兩個(gè)私有靜態(tài)字段:
(第 45 行)
第 49 行到第 53 行的靜態(tài)構(gòu)造函數(shù)對(duì) newlineChar 字段有條件地賦值。
第 55 行到第 103 行的十個(gè)構(gòu)造函數(shù)僅是調(diào)用基類(lèi) StreamReader 對(duì)應(yīng)的構(gòu)造函數(shù)而已。
第 105 行到第 123 行以及第 182 行到第 200 行的四個(gè)方法重寫(xiě)了基類(lèi) StreamReader 中對(duì)應(yīng)的虛方法。簡(jiǎn)單地調(diào)用基類(lèi)中對(duì)應(yīng)的虛方法,捕獲并忽略 IOException 異常。
第 125 行到第 163 行的 Read 方法也是重寫(xiě)了基類(lèi)的虛方法,可是它沒(méi)有簡(jiǎn)單地調(diào)用基類(lèi)中對(duì)應(yīng)的虛方法。
它首先檢查輸入的參數(shù)是否合法。然后在循環(huán)中調(diào)用基類(lèi)的還有一個(gè) Read 方法一個(gè)個(gè)地讀取字符,捕獲并忽略 IOException 異常。注意這個(gè) Read 方法的語(yǔ)義不同于其基類(lèi) StreamReader 中對(duì)應(yīng)的 Read 方法的語(yǔ)義,前者遇到 EOL 就提前返回,而后者要遇到 EOF 才會(huì)提前返回。
第 165 行到第 180 行的 CheckEOL 方法是私有(private)方法,僅在第 154 行被調(diào)用過(guò),用于在?Environment.NewLine?不止一個(gè)字符時(shí)(在 Windows 操作系統(tǒng)中就是如此。其值為”\r\n”,而在 Unix 操作系統(tǒng)中其值為”\n”)推斷是否遇到了行結(jié)束符。即 EOL,也就是 Environment.NewLine。
在 Console.dll 項(xiàng)目中。UnexceptionalStreamReader 類(lèi)在 Console.cs 中被使用過(guò)一次。
在上述源程序的第 34 行到第 37 行的凝視中也已經(jīng)指出了這一點(diǎn)。
UnexceptionalStreamWriter 類(lèi) (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 類(lèi)。該類(lèi)位于 System.IO 命名空間中,繼承自 StreamWriter 類(lèi),是 internal 的。即僅僅能在本程序集中使用。
第 2 行的凝視“System.IO.StreamWriter.cs”有誤,應(yīng)改為“System.IO.UnexceptionStreamWriter”。
UnexceptionalStreamWriter 類(lèi)是對(duì) StreamWriter 類(lèi)的包裝,捕獲并忽略全部的 IOException 異常。
它用于 Console 類(lèi)中。以免 IO 錯(cuò)誤干擾控制臺(tái)的正常執(zhí)行。
第 46 行到第 85 行的七個(gè)構(gòu)造函數(shù)僅是調(diào)用基類(lèi) StreamWriter 對(duì)應(yīng)的構(gòu)造函數(shù)而已。
第 87 行到第 126 行的五個(gè)方法重寫(xiě)了基類(lèi) StreamWriter 中對(duì)應(yīng)的虛方法,簡(jiǎn)單地調(diào)用基類(lèi)中對(duì)應(yīng)的虛方法,捕獲并忽略 IOException 異常。
在 Console.dll 項(xiàng)目中,UnexceptionStreamWriter 類(lèi)在 Console.cs 中被使用過(guò)兩次。
總結(jié)
以上是生活随笔為你收集整理的Mono源码学习笔记:Console类(四)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: jQuery的Autocomplete插
- 下一篇: Spring Security 入门(3