在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
目录概述事件起因,一哥们在群里面贴出了类似下面这样的一段代码: 1 class Program 2 { 3 static void Main(string[] args) 4 { 5 byte[] buffer = File.ReadAllBytes("test.txt"); 6 MemoryStream ms = new MemoryStream(buffer); 7 ms.Dispose(); 8 Console.WriteLine(ms.ToArray().Length); 9 Console.Read(); 10 } 11 } 先不去考究这段代码到底有没有什么意义,就代码而言,内存流释放之后,再去使用ms会有问题么? 运行结果:
那我们如果访问ms对象的其他的属性(ms.Length)会怎么样呢? 访问其它的方法它也会出现上面的异常。 这问题出来了,难道内存流的Dispose方法是选择性的释放? 在看MemoryStream分析之前,回顾一下托管与非托管资源的概念。
MemoryStream分析对于这个问题,吃饭的时候一直很纠结,所以就查了一些这方面的资料,也试图反编译MemoryStream类,看看Dispose方法是如何实现。 参考: http://stackoverflow.com/questions/4274590/memorystream-close-or-memorystream-dispose github上MemoryStream中的代码: 1 // 2 // System.IO.MemoryStream.cs 3 // 4 // Authors: Marcin Szczepanski ([email protected]) 5 // Patrik Torstensson 6 // Gonzalo Paniagua Javier ([email protected]) 7 // Marek Safar ([email protected]) 8 // 9 // (c) 2001,2002 Marcin Szczepanski, Patrik Torstensson 10 // (c) 2003 Ximian, Inc. (http://www.ximian.com) 11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com) 12 // Copyright 2011 Xamarin, Inc (http://www.xamarin.com) 13 // 14 // Permission is hereby granted, free of charge, to any person obtaining 15 // a copy of this software and associated documentation files (the 16 // "Software"), to deal in the Software without restriction, including 17 // without limitation the rights to use, copy, modify, merge, publish, 18 // distribute, sublicense, and/or sell copies of the Software, and to 19 // permit persons to whom the Software is furnished to do so, subject to 20 // the following conditions: 21 // 22 // The above copyright notice and this permission notice shall be 23 // included in all copies or substantial portions of the Software. 24 // 25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 // 33 34 using System.Globalization; 35 using System.Runtime.InteropServices; 36 using System.Threading; 37 #if NET_4_5 38 using System.Threading.Tasks; 39 #endif 40 41 namespace System.IO 42 { 43 [Serializable] 44 [ComVisible (true)] 45 [MonoLimitation ("Serialization format not compatible with .NET")] 46 public class MemoryStream : Stream 47 { 48 bool canWrite; 49 bool allowGetBuffer; 50 int capacity; 51 int length; 52 byte [] internalBuffer; 53 int initialIndex; 54 bool expandable; 55 bool streamClosed; 56 int position; 57 int dirty_bytes; 58 #if NET_4_5 59 [NonSerialized] 60 Task<int> read_task; 61 #endif 62 63 public MemoryStream () : this (0) 64 { 65 } 66 67 public MemoryStream (int capacity) 68 { 69 if (capacity < 0) 70 throw new ArgumentOutOfRangeException ("capacity"); 71 72 canWrite = true; 73 74 this.capacity = capacity; 75 internalBuffer = new byte [capacity]; 76 77 expandable = true; 78 allowGetBuffer = true; 79 } 80 81 public MemoryStream (byte [] buffer) 82 { 83 if (buffer == null) 84 throw new ArgumentNullException ("buffer"); 85 86 InternalConstructor (buffer, 0, buffer.Length, true, false); 87 } 88 89 public MemoryStream (byte [] buffer, bool writable) 90 { 91 if (buffer == null) 92 throw new ArgumentNullException ("buffer"); 93 94 InternalConstructor (buffer, 0, buffer.Length, writable, false); 95 } 96 97 public MemoryStream (byte [] buffer, int index, int count) 98 { 99 InternalConstructor (buffer, index, count, true, false); 100 } 101 102 public MemoryStream (byte [] buffer, int index, int count, bool writable) 103 { 104 InternalConstructor (buffer, index, count, writable, false); 105 } 106 107 public MemoryStream (byte [] buffer, int index, int count, bool writable, bool publiclyVisible) 108 { 109 InternalConstructor (buffer, index, count, writable, publiclyVisible); 110 } 111 112 void InternalConstructor (byte [] buffer, int index, int count, bool writable, bool publicallyVisible) 113 { 114 if (buffer == null) 115 throw new ArgumentNullException ("buffer"); 116 117 if (index < 0 || count < 0) 118 throw new ArgumentOutOfRangeException ("index or count is less than 0."); 119 120 if (buffer.Length - index < count) 121 throw new ArgumentException ("index+count", 122 "The size of the buffer is less than index + count."); 123 124 canWrite = writable; 125 126 internalBuffer = buffer; 127 capacity = count + index; 128 length = capacity; 129 position = index; 130 initialIndex = index; 131 132 allowGetBuffer = publicallyVisible; 133 expandable = false; 134 } 135 136 void CheckIfClosedThrowDisposed () 137 { 138 if (streamClosed) 139 throw new ObjectDisposedException ("MemoryStream"); 140 } 141 142 public override bool CanRead { 143 get { return !streamClosed; } 144 } 145 146 public override bool CanSeek { 147 get { return !streamClosed; } 148 } 149 150 public override bool CanWrite { 151 get { return (!streamClosed && canWrite); } 152 } 153 154 public virtual int Capacity { 155 get { 156 CheckIfClosedThrowDisposed (); 157 return capacity - initialIndex; 158 } 159 160 set { 161 CheckIfClosedThrowDisposed (); 162 163 if (!expandable) 164 throw new NotSupportedException ("Cannot expand this MemoryStream"); 165 166 if (value < 0 || value < length) 167 throw new ArgumentOutOfRangeException ("value", 168 "New capacity cannot be negative or less than the current capacity " + value + " " + capacity); 169 170 if (internalBuffer != null && value == internalBuffer.Length) 171 return; 172 173 byte [] newBuffer = null; 174 if (value != 0) { 175 newBuffer = new byte [value]; 176 if (internalBuffer != null) 177 Buffer.BlockCopy (internalBuffer, 0, newBuffer, 0, length); 178 } 179 180 dirty_bytes = 0; // discard any dirty area beyond previous length 181 internalBuffer = newBuffer; // It's null when capacity is set to 0 182 capacity = value; 183 } 184 } 185 186 public override long Length { 187 get { 188 // LAMESPEC: The spec says to throw an IOException if the 189 // stream is closed and an ObjectDisposedException if 190 // "methods were called after the stream was closed". What 191 // is the difference? 192 193 CheckIfClosedThrowDisposed (); 194 195 // This is ok for MemoryStreamTest.ConstructorFive 196 return length - initialIndex; 197 } 198 } 199 200 public override long Position { 201 get { 202 CheckIfClosedThrowDisposed (); 203 return position - initialIndex; 204 } 205 206 set { 207 CheckIfClosedThrowDisposed (); 208 if (value < 0) 209 throw new ArgumentOutOfRangeException ("value", 210 "Position cannot be negative" ); 211 212 if (value > Int32.MaxValue) 213 throw new ArgumentOutOfRangeException ("value", 214 "Position must be non-negative and less than 2^31 - 1 - origin"); 215 216 position = initialIndex + (int) value; 217 } 218 } 219 220 protected override void Dispose (bool disposing) 221 { 222 streamClosed = true; 223 expandable = false; 224 } 225 226 public override void Flush () 227 { 228 // Do nothing 229 } 230 231 public virtual byte [] GetBuffer () 232 { 233 if (!allowGetBuffer) 234 throw new UnauthorizedAccessException (); 235 236 return internalBuffer; 237 } 238 239 public override int Read ([In,Out] byte [] buffer, int offset, int count) 240 { 241 if (buffer == null) 242 throw new ArgumentNullException ("buffer"); 243 244 if (offset < 0 || count < 0) 245 throw new ArgumentOutOfRangeException ("offset or count less than zero."); 246 247 if (buffer.Length - offset < count ) 248 throw new ArgumentException ("offset+count", 249 "The size of the buffer is less than offset + count."); 250 251 CheckIfClosedThrowDisposed (); 252 253 if (position >= length || count == 0) 254 return 0; 255 256 if (position > length - count) 257 count = length - position; 258 259 Buffer.BlockCopy (internalBuffer, position, buffer, offset, count); 260 position += count; 261 return count; 262 } 263 264 public override int ReadByte () 265 { 266 CheckIfClosedThrowDisposed (); 267 if (position >= length) 268 return -1; 269 270 return internalBuffer [position++]; 271 } 272 273 public override long Seek (long offset, SeekOrigin loc) 274 { 275 CheckIfClosedThrowDisposed (); 276 277 // It's funny that they don't throw this exception for < Int32.MinValue 278 if (offset > (long) Int32.MaxValue) 279 throw new ArgumentOutOfRangeException ("Offset out of range. " + offset); 280 281 int refPoint; 282 switch (loc) { 283 case SeekOrigin.Begin: 284 if (offset < 0) 285 throw new IOException ("Attempted to seek before start of MemoryStream."); 286 refPoint = initialIndex; 287 break; 288 case SeekOrigin.Current: 289 refPoint = position; 290 break |
请发表评论