You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何MemoryStream无Memory<byte>构造函数?非重新分配数组的替代方案

问题

为何不存在new MemoryStream(Memory<byte> buffer)或new MemoryStream(ReadOnlyMemory<byte> buffer)构造函数?除了重新分配新字节数组之外,还有哪些解决方法?

我有一个用于解析的API(来自Bouncy Castle C#),定义如下:

var parsed = HeartbeatMessage.Parse(Stream stream); 

目前我持有Memory<byte>类型的实际数据,期望能进行如下调用:

Memory<byte> buffer = .... // data 
var parsed =  HeartbeatMessage.Parse(new MemoryStream(buffer)); 
解答

一、为什么没有直接的Memory<byte>/ReadOnlyMemory<byte>构造函数?

MemoryStream的核心设计依赖连续托管字节数组的直接操作,而Memory<byte>/ReadOnlyMemory<byte>的底层存储非常灵活:它可以是堆外内存、数组切片后的非连续段,甚至是自定义内存实现。如果强行绑定这类非标准内存,MemoryStream内部的数组操作逻辑会彻底失效,这是两者设计目标不匹配导致的。

二、无需重新分配数组的解决方法

1. 提取底层数组段(适用于托管数组底层的Memory<byte>)

如果你的Memory<byte>是基于标准托管数组的,可以用MemoryMarshal.TryGetArray直接获取数组和偏移信息,再传入MemoryStream的重载构造函数,完全避免内存复制:

Memory<byte> buffer = ...;
if (MemoryMarshal.TryGetArray(buffer, out ArraySegment<byte> segment))
{
    using var ms = new MemoryStream(segment.Array, segment.Offset, segment.Count);
    var parsed = HeartbeatMessage.Parse(ms);
}
else
{
    // 处理非托管/非数组底层的特殊场景,此时可能仍需复制(但这类情况较少见)
}

2. 自定义适配Memory<byte>的Stream实现

如果需要频繁处理非托管底层的Memory<byte>,可以实现一个轻量的Stream子类,直接包装Memory<byte>进行读写:

public class MemoryStreamWrapper : Stream
{
    private readonly Memory<byte> _memory;
    private int _position;

    public MemoryStreamWrapper(Memory<byte> memory)
    {
        _memory = memory;
    }

    public override bool CanRead => true;
    public override bool CanSeek => true;
    public override bool CanWrite => false; // 可根据需求改为true并实现Write逻辑
    public override long Length => _memory.Length;

    public override long Position
    {
        get => _position;
        set => _position = (int)Math.Clamp(value, 0, Length);
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        int bytesToRead = Math.Min(count, (int)(Length - Position));
        _memory.Slice(_position, bytesToRead).CopyTo(buffer.AsMemory(offset));
        _position += bytesToRead;
        return bytesToRead;
    }

    public override long Seek(long offset, SeekOrigin origin)
    {
        switch (origin)
        {
            case SeekOrigin.Begin:
                Position = offset;
                break;
            case SeekOrigin.Current:
                Position += offset;
                break;
            case SeekOrigin.End:
                Position = Length + offset;
                break;
        }
        return Position;
    }

    // 按需实现或抛出异常的方法
    public override void Flush() { }
    public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
    public override void SetLength(long value) => throw new NotSupportedException();
}

使用示例:

Memory<byte> buffer = ...;
using var ms = new MemoryStreamWrapper(buffer);
var parsed = HeartbeatMessage.Parse(ms);

这个方案适配所有Memory<byte>场景,全程无内存复制。

3. 查找Bouncy Castle的替代重载

部分Bouncy Castle的解析类会提供直接接受byte[]或ReadOnlySpan<byte>的重载,你可以检查HeartbeatMessage是否有类似方法:

// 假设存在该重载
var parsed = HeartbeatMessage.Parse(buffer.Span);

如果有这类重载,这是最简洁高效的解决方案。


内容的提问来源于stack exchange,提问作者Perfect28

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 17:40:14