假设我有一个MemoryStream
和一个按字节操作的函数。
目前的代码是这样的:
void caller()
{
MemoryStream ms = // not important
func(ms.GetBuffer(), 0, (int)ms.Length);
}
void func(byte[] buffer, int offset, int length)
{
// not important
}
我无法更改func
,但我希望尽量减少在func
内更改流数据的可能性。
我怎样才能/应该重写代码以确保不会更改流数据?
或者这不能做到?
编辑:
对不起,我没有提到我想不复制数据。
答案 0 :(得分:5)
致电.ToArray
。
func(ms.GetBuffer().ToArray(), 0, (int)ms.Length);
来自MSDN(强调我的):
请注意,缓冲区包含可能未使用的已分配字节。 例如,如果字符串“test”被写入MemoryStream 对象,从GetBuffer返回的缓冲区的长度是256,而不是 4,未使用252字节。 要仅获取缓冲区中的数据,请使用 ToArray方法;但是,ToArray会在其中创建数据的副本 存储器强>
理想情况下,您可以将func
更改为IEnumerable<byte>
。一旦方法具有数组,您就相信如果您不希望它们,则不会修改数据。如果合同 提供IEnumerable<byte>
,则实施者必须决定是否需要副本进行编辑。
答案 1 :(得分:3)
如果您无法复制(ToArray,如其他答案所示)并且无法更改func
函数的签名,则唯一剩下的就是尝试验证该函数是否未更改数据。
您可以在通话之前/之后计算某种哈希值并检查它是否相同。它不能保证func没有改变底层数据(由于哈希冲突),但至少会给你很好的机会来知道它是否发生。可能对非生产代码很有用......
真正的解决方案是将数据副本提供给不受信任的代码,或者传递一些不允许数据更改的包装器接口/对象(需要对func
进行签名更改/重写)。
答案 2 :(得分:2)
使用ms.ToArray()
将数据复制出流。显然,会有性能受到打击。
答案 3 :(得分:2)
您不能仅将数组的“切片”传递给方法。您将数组的副本传递给方法并将结果复制回来:
byte[] slice = new byte[length];
Buffer.BlockCopy(bytes, offset, slice, 0, length);
func(slice, 0, length);
Buffer.BlockCopy(slice, 0, bytes, offset, length);
或者,如果您可以更改方法,则传递某种包装数组的代理对象,并检查每个访问是否在允许的范围内:
class ArrayView<T>
{
private T[] array;
private int offset;
private int length;
public T this[int index]
{
get
{
if (index < offset || index >= offset + length)
throw new ArgumentOutOfRange("index");
return array[index];
}
set
{
if (index < offset || index >= offset + length)
throw new ArgumentOutOfRange("index");
array[index] = value;
}
}
}
答案 4 :(得分:0)
您是否尝试确保func()
实际上永远无法更改内存流,或者如果 更改了某些内容,您的代码是否会引发异常,这是否足够?听起来像你想要做的事情:
void caller()
{
MemoryStream ms = // not important
var checksum = CalculateMyChecksum(ms);
func(ms.GetBuffer(), 0, (int)ms.Length);
if(checksum != CalculateMyChecksum(ms)){
throw new Exception("Hey! Someone has been fiddling with my memory!");
}
}
虽然对于任何重要/重要的事情,我都不会感到很自在。你能提供更多信息吗?也许有更好的解决方案可以解决您的问题,并且可以完全避免这个问题。