C# programming
Data Conversion
Software Development
ReadOnlyMemory
Programming Arrays

C# Convert ReadOnlyMemory<byte> to byte[]

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In C#, converting ReadOnlyMemory<byte> to byte[] is easy, but the right method depends on whether you want a copy or you want to reuse an underlying array. The safest general answer is ToArray(), while zero-copy access is only possible in some cases and requires more care.

The Simple and Safe Approach

If you need a real byte array and do not care about allocating a copy, use ToArray():

csharp
1using System;
2
3class Program
4{
5    static void Main()
6    {
7        ReadOnlyMemory<byte> memory = new byte[] { 10, 20, 30, 40 };
8        byte[] bytes = memory.ToArray();
9
10        Console.WriteLine(string.Join(", ", bytes));
11    }
12}

This always creates a new byte[]. That means:

  • it is safe
  • it works regardless of how the memory was created
  • changes to the new array do not affect the original source

For most application code, this is the best default.

Why ReadOnlyMemory<byte> Exists

ReadOnlyMemory<byte> is often used to pass byte data around without forcing immediate copies. It can represent:

  • a full array
  • a slice of an array
  • memory from other sources exposed through the memory abstractions

That flexibility is exactly why converting to byte[] is not always free. A byte array requires one concrete owned buffer, while ReadOnlyMemory<byte> is more general.

Zero-Copy Access When the Memory Is Array-Backed

If the memory came from an array, you may be able to get access to that underlying array using MemoryMarshal.TryGetArray.

csharp
1using System;
2using System.Runtime.InteropServices;
3
4class Program
5{
6    static void Main()
7    {
8        ReadOnlyMemory<byte> memory = new byte[] { 1, 2, 3, 4, 5 };
9
10        if (MemoryMarshal.TryGetArray(memory, out ArraySegment<byte> segment))
11        {
12            Console.WriteLine(segment.Array != null);
13            Console.WriteLine(segment.Offset);
14            Console.WriteLine(segment.Count);
15        }
16    }
17}

This does not guarantee that the returned segment.Array is exactly the logical slice you want. You may need to respect Offset and Count.

That is why treating segment.Array as the final answer can be wrong if the ReadOnlyMemory<byte> is only a slice of a larger array.

Handling Slices Correctly

Consider this:

csharp
1using System;
2using System.Runtime.InteropServices;
3
4class Program
5{
6    static void Main()
7    {
8        byte[] source = { 10, 20, 30, 40, 50 };
9        ReadOnlyMemory<byte> memory = source.AsMemory(1, 3);
10
11        if (MemoryMarshal.TryGetArray(memory, out ArraySegment<byte> segment))
12        {
13            Console.WriteLine(string.Join(", ", segment.Array!));
14            Console.WriteLine($"Offset={segment.Offset}, Count={segment.Count}");
15        }
16    }
17}

The underlying array is still the full source, not only the logical three-byte slice. If you need an exact standalone array for that slice, ToArray() is still the cleanest choice.

When You Should Avoid Converting

Sometimes the best answer is not to convert at all. Many modern .NET APIs accept ReadOnlyMemory<byte> or ReadOnlySpan<byte>. If the next API can already consume memory safely, keeping the existing type avoids unnecessary allocation.

That can matter in:

  • high-throughput networking
  • parsing pipelines
  • serialization code
  • streaming systems

The need to convert often comes from an older API boundary rather than from the data itself.

A Copy into a Preallocated Array

If you want control over allocation, you can create the destination yourself and copy into it:

csharp
1using System;
2
3class Program
4{
5    static void Main()
6    {
7        ReadOnlyMemory<byte> memory = new byte[] { 5, 6, 7 };
8        byte[] destination = new byte[memory.Length];
9
10        memory.Span.CopyTo(destination);
11        Console.WriteLine(string.Join(", ", destination));
12    }
13}

This still copies, but it lets you decide where the destination buffer comes from.

Common Pitfalls

The most common mistake is assuming that TryGetArray always returns a perfectly sized standalone array. It does not; it may expose a larger array plus an offset and count.

Another issue is converting automatically with ToArray() in hot paths without measuring allocations. It is correct, but it may be more expensive than necessary if the next API already accepts spans or memory.

A third pitfall is forgetting that ReadOnlyMemory<byte> being read-only does not guarantee the underlying array can never change elsewhere. Read-only describes the view, not universal immutability.

Summary

  • Use ToArray() when you need a simple, exact byte[].
  • 'MemoryMarshal.TryGetArray can avoid copying only when the memory is array-backed.'
  • Respect ArraySegment.Offset and Count if you expose the underlying array.
  • Prefer staying in ReadOnlyMemory<byte> or ReadOnlySpan<byte> when downstream APIs allow it.
  • Choose the conversion method based on whether correctness, allocation cost, or zero-copy access matters most.

Course illustration
Course illustration

All Rights Reserved.