Skip to content

Add Memory<byte> and ReadOnlyMemory<byte> constructors to MemoryStream#124990

Draft
Copilot wants to merge 4 commits intomainfrom
copilot/add-memorystream-constructors
Draft

Add Memory<byte> and ReadOnlyMemory<byte> constructors to MemoryStream#124990
Copilot wants to merge 4 commits intomainfrom
copilot/add-memorystream-constructors

Conversation

Copy link
Contributor

Copilot AI commented Feb 27, 2026

Description

Adds ReadOnlyMemory<byte> and Memory<byte> constructors to MemoryStream using a delegation pattern that avoids any performance penalty for existing byte-array code paths.

A private inner class MemoryMemoryStream holds all Memory-backed state and operations. A readonly field _memoryMemoryStream is only set by the new constructors — in all existing constructors it remains null. Every public/override method checks this field first:

public override int ReadByte()
{
    if (_memoryMemoryStream is not null)
        return _memoryMemoryStream.ReadByte();

    // existing byte-array implementation unchanged
    EnsureNotClosed();
    if (_position >= _length) return -1;
    return _buffer[_position++];
}

New constructors

  • MemoryStream(ReadOnlyMemory<byte>) — read-only, non-expandable
  • MemoryStream(Memory<byte>) — writable, non-expandable
  • MemoryStream(Memory<byte>, bool writable) — writability control

Key design decisions

  • Zero perf regression: Existing callers pay only one null-check per method call. No virtual dispatch, no interface indirection.
  • BinaryReader compatibility: BinaryReader.ReadCharsCommon used InternalGetBuffer()/InternalGetPosition() which return byte[] — not viable for arbitrary Memory<byte>. Added InternalRead(int count) that returns ReadOnlySpan<byte> and works for both paths.
  • Non-expandable: Memory-backed streams behave like MemoryStream(byte[], writable) — fixed capacity, SetLength within capacity is allowed, expansion throws NotSupportedException.
  • GetBuffer/TryGetBuffer: GetBuffer() throws UnauthorizedAccessException, TryGetBuffer() returns false (no underlying byte[] to expose).
  • ToArray after Dispose: Works, matching existing byte-array MemoryStream behavior.

Files changed

File Change
MemoryStream.cs Inner class, 3 constructors, delegation in all methods, InternalRead
BinaryReader.cs Use InternalRead instead of InternalGetBuffer/InternalGetPosition
System.Runtime.cs Ref API surface
MemoryStreamTests.cs 23 new tests

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-system-memory
See info in area-owners.md if you want to be subscribed.

Copilot AI and others added 3 commits February 27, 2026 23:07
…m with delegation pattern

Co-authored-by: jozkee <16040868+jozkee@users.noreply.github.com>
…tructors

Co-authored-by: jozkee <16040868+jozkee@users.noreply.github.com>
…ternalRead method

Co-authored-by: jozkee <16040868+jozkee@users.noreply.github.com>
Copilot AI changed the title [WIP] Add ReadOnlyMemory and Memory constructors to MemoryStream Add Memory<byte> and ReadOnlyMemory<byte> constructors to MemoryStream Feb 27, 2026

private sealed class MemoryMemoryStream
{
private readonly ReadOnlyMemory<byte> _memory;
Copy link
Member

@jkotas jkotas Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Store only ReadOnlyMemory/Memory here and use the rest of the state from the main Stream?

It would reduce the overall instance size and it would make it unnecessary to the switch in some of the properties, e.g. Length or Position.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants