如何不调用.ToArray()从ReadOnlySpan<byte>获取byte[]?以及调用遗留API时避免数组转换的实现方法
ToArray() when passing ReadOnlySpan<byte> to a legacy API expecting byte[]? Great question—this is a common pain point when mixing modern span-based code with older .NET APIs. Let’s break down what’s possible, what’s not, and how to handle it:
First: Can I get a byte[] from ReadOnlySpan<byte> without calling ToArray()?
Short answer: Only if the ReadOnlySpan<byte> is backed by a managed array. And even then, you need to proceed with caution.
The MemoryMarshal.TryGetArray method is specifically built for this scenario—it lets you extract the underlying array segment from a span (or memory) if it exists. Here’s how to use it:
ReadOnlySpan<byte> inputReadOnlyParam = ...; if (MemoryMarshal.TryGetArray(inputReadOnlyParam, out ArraySegment<byte> segment)) { // We successfully retrieved the underlying array! byte[] underlyingArray = segment.Array; // Critical notes to remember: // 1. segment.Offset and segment.Count tell you exactly where the span starts/ends in the array // If your span was a slice of the array, the full array includes extra data outside the span's bounds // 2. The original span was marked as "readonly"—modifying this array could break assumptions in the code that created the span } else { // The span isn't backed by a managed array (e.g., it points to stack memory, unmanaged memory, or a custom memory source) // In this case, you *must* call ToArray() to copy the data into a safe managed array }
Why can’t we always get the underlying array? Because ReadOnlySpan<T> is designed to work with all types of memory—not just managed arrays. For example, if the span points to stack memory, passing that to an API expecting a byte[] (which lives on the GC heap) would cause memory corruption once the stack frame is cleaned up.
Second: How to call the legacy API without ToArray()?
Your legacy API signature is:
public byte[] ProcessAndCreateNewArray(byte[] readonlyParam);
Whether you can skip ToArray() depends on two factors: the API’s behavior and your span’s backing memory.
1. If the API only reads from readonlyParam (no modifications)
- Use
MemoryMarshal.TryGetArrayto get the underlying array. - If your span covers the entire array (segment.Offset == 0 and segment.Count == underlyingArray.Length), you can pass
underlyingArraydirectly to the API. - If your span is a slice of the array: Ask yourself—does the API expect only the span’s data, or the full array? If it needs only the span’s data, you still need to copy that slice to a new array (since the API takes a full
byte[]). The only way around this is modifying the legacy API to acceptReadOnlySpan<byte>instead.
2. If the API modifies the input array
- Do not pass the underlying array from the span. The
ReadOnlySpan<T>contract promises the memory won’t be modified, so breaking this could introduce bugs or data corruption. You must callToArray()to create a safe copy for the API to modify.
What if TryGetArray returns false?
If your span isn’t backed by a managed array (e.g., stack memory, unmanaged memory), you have no choice but to call ToArray(). This copies the span’s data into a new managed array that the legacy API can safely use.
Final Takeaways
- You can skip
ToArray()only when theReadOnlySpan<byte>is backed by a managed array, and the legacy API’s usage of the input aligns with the span’s bounds and readonly contract. - In all other cases,
ToArray()is necessary to ensure safe, correct behavior.
内容的提问来源于stack exchange,提问作者Veksi

