关于MemoryStream类
许多人认为MemoryStream是无法进行扩展的,其实不然;为了更好了解MemoryStream,我不得不研究MemoryStream的源代码,首先看空构造函数(以下代码均是Reflector Pro版本反射得到):
[C#]
public MemoryStream() : this(0)
{
}
public MemoryStream(int capacity)
{
if (capacity < 0)
{
throw new ArgumentOutOfRangeException("capacity", Environment.GetResourceString("ArgumentOutOfRange_NegativeCapacity"));
}
this._buffer = new byte[capacity];
this._capacity = capacity;
this._expandable = true;
this._writable = true;
this._exposable = true;
this._origin = 0;
this._isOpen = true;
}
[VB.NET]
Public Sub New()
Me.New(0)
End Sub
Public Sub New(ByVal capacity As Integer)
If (capacity < 0) Then
Throw New ArgumentOutOfRangeException("capacity", Environment.GetResourceString("ArgumentOutOfRange_NegativeCapacity"))
End If
Me._buffer = New Byte(capacity - 1) {}
Me._capacity = capacity
Me._expandable = True
Me._writable = True
Me._exposable = True
Me._origin = 0
Me._isOpen = True
End Sub
从代码中可以知道——MemoryStream内部存放的一个内存数组,当空构造函数的时候,该数组的实际容量为0;然后调用Write函数的时候……
[C#]
public override void Write(byte[] buffer, int offset, int count)
{
//省去其它部分……
int num = this._position + count;
if (num > this._length)
{
bool flag = this._position > this._length;
if ((num > this._capacity) && this.EnsureCapacity(num))
{
flag = false;
}
if (flag)
{
Array.Clear(this._buffer, this._length, num - this._length);
}
this._length = num;
}
if ((count <= 8) && (buffer != this._buffer))
{
int num2 = count;
while (--num2 >= 0)
{
this._buffer[this._position + num2] = buffer[offset + num2];
}
}
else
{
Buffer.InternalBlockCopy(buffer, offset, this._buffer, this._position, count);
}
this._position = num;
}
[VB.NET]
Public Overrides Sub Write(buffer__1 As Byte(), offset As Integer, count As Integer)
'省去其它部分……
Dim num As Integer = (Me._position + count)
If num > Me._length Then
Dim flag As Boolean = Me._position > Me._length
If (num > Me._capacity) AndAlso Me.EnsureCapacity(num) Then
flag = False
End If
If flag Then
Array.Clear(Me._buffer, Me._length, num - Me._length)
End If
Me._length = num
End If
If (count <= 8) AndAlso (buffer<> Me._buffer) Then
Dim num2 As Integer = count
Do While (--num2 >= 0) Me._buffer((Me._position + num2)) = buffer((offset + num2)) Loop
Else
Buffer.InternalBlockCopy(buffer__1, offset, Me._buffer, Me._position, count)
End If
Me._position = num
End Sub
以上代码大致的意思是:先检测内部剩余空间是否足够容纳外部buffer要写入的字节数(count),如果探测发现内部数组剩余空间不够的话,那么自动扩容——请注意EnsureCapacity函数,反编译结果如下:
[C#]
private bool EnsureCapacity(int value)
{
if (value < 0)
{
throw new IOException(Environment.GetResourceString("IO.IO_StreamTooLong"));
}
if (value <= this._capacity)
{
return false;
}
int num = value;
if (num < 0x100)
{
num = 0x100;
}
if (num < (this._capacity * 2))
{
num = this._capacity * 2;
}
this.Capacity = num;
return true;
}
[VB.NET]
从反编译结果可以明显看到,MemoryStream在使用第一、第二构造函数的时候(指定capability的时候,非直接传入一个byte数组的时候)是可以进行扩容的。扩容情况如下:
1)当实际需要的容量小于256个字节,自动扩容到256;
2)当实际需要的容量小于实际容量的2倍的时候,自动扩容到自身容量的2倍。
而真正扩容的地方在属性Capacity中——
[C#]
public virtual int Capacity
{
//省略其它部分……
if (this._expandable && (value != this._capacity))
{
if (value > 0)
{
byte[] dst = new byte[value];
if (this._length > 0)
{
Buffer.InternalBlockCopy(this._buffer, 0, dst, 0, this._length);
}
this._buffer = dst;
}
else
{
this._buffer = null;
}
this._capacity = value;
}
}
}
[VB.NET]
Public Overridable Property Capacity As Integer
'省略其它部分……
If (Me._expandable AndAlso (value <> Me._capacity)) Then
If (value > 0) Then
Dim dst As Byte() = New Byte(value - 1) {}
If (Me._length > 0) Then
Buffer.InternalBlockCopy(Me._buffer, 0, dst, 0, Me._length)
End If
Me._buffer = dst
Else
Me._buffer = Nothing
End If
Me._capacity = value
End If
End Set
End Property
可见,.NET类库做的是“先生成新数组,然后使用内部底层的InteralBlockCopy进行批量拷贝。不过请注意————expandable是一个条件,该条件决定MemoryStream是否允许扩容,而这个私有变量在MemoryStream上面给出的两个构造函数中充分显示了。因此只有在使用MemoryStream的第一、二构造函数的时候才允许扩容,其余时候都是不允许的(因为默认expandable=false,布尔值默认是false)。