2

假设我有一个MemoryStream对字节进行操作的 and 函数。

当前代码是这样的:

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.

我如何/应该重写代码以确保不会更改流数据?

或者这不能做?

编辑:

对不起,我没有提到我不想复制数据。

4

5 回答 5

5

打电话.ToArray

func(ms.GetBuffer().ToArray(), 0, (int)ms.Length);

来自MSDN(重点是我的):

请注意,缓冲区包含可能未使用的已分配字节。例如,如果将字符串“test”写入 MemoryStream 对象,则从 GetBuffer 返回的缓冲区长度为 256,而不是 4,其中 252 个字节未使用。要仅获取缓冲区中的数据,请使用 ToArray 方法;但是,ToArray 会在内存中创建数据的副本。


理想情况下,您会更改funcIEnumerable<byte>. 一旦方法拥有数组,您就相信如果您不希望它们修改数据,它们不会修改数据。如果合同提供IEnumerable<byte>,实施者将不得不决定他们是否需要一份副本来编辑。

于 2012-09-06T16:43:11.503 回答
3

如果您无法复制(其他答案中建议的 ToArray)并且无法更改func函数的签名,那么剩下的唯一事情就是尝试验证该函数没有更改数据。

您可以在调用之前/之后计算某种哈希值并检查它是否相同。它不能保证 func 没有改变底层数据(由于哈希冲突),但至少会给你很好的机会知道它是否发生了。可能对非生产代码有用...

真正的解决方案是要么将数据副本提供给不受信任的代码,要么传递一些不允许数据更改的包装接口/对象(需要更改签名/重写func)。

于 2012-09-06T16:52:12.203 回答
2

使用 将数据从流中复制出来ms.ToArray()。显然,性能会受到影响。

于 2012-09-06T16:42:49.683 回答
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;
        }
    }
}
于 2012-09-06T16:47:22.067 回答
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!");
    }
}

不过,对于任何重要/关键的事情,我都不愿意推荐这个。你能提供更多信息吗?也许对您的问题有更好的解决方案,以及完全避免此问题的方法。

于 2012-09-06T17:27:45.013 回答