在C#里,Memory<T>和ReadOnlyMemory<T>是System命名空间下表示连续内存区域的轻量结构。它们不直接持有数据,而是对数组、字符串或自定义内存池的视图包装,能在栈和堆之间安全传递,避免拷贝与指针风险。

Memory与ReadOnlyMemory基础
Memory<T>允许读写底层内存,ReadOnlyMemory<T>则限制为只读,适合传递不应被修改的数据。二者都可从数组、字符串轻松创建。
using System;
class Demo
{
static void Main()
{
int[] arr = { 1, 2, 3, 4, 5 };
// 从数组创建可读写内存视图
Memory<int> mem = arr;
// 从字符串创建只读内存
ReadOnlyMemory<char> rom = "hello".AsMemory();
Console.WriteLine(mem.Length);
Console.WriteLine(rom.Span[0]);
}
}
切分内存视图
使用Slice方法可得到子区域视图,不产生新数组,仅偏移指针与长度,是内存安全操作的核心手段。
using System;
class SliceDemo
{
static void Main()
{
int[] data = { 10, 20, 30, 40, 50 };
Memory<int> mem = data;
// 取索引1开始长度为3的视图
Memory<int> slice = mem.Slice(1, 3);
foreach (var i in slice.Span)
{
Console.WriteLine(i);
}
}
}
只读场景的保护
当方法只读取内容时,参数声明为ReadOnlyMemory<T>可阻止调用方意外修改,也明确表达设计意图。
using System;
class ReadOnlyDemo
{
static void Print(ReadOnlyMemory<char> text)
{
foreach (var c in text.Span)
{
Console.Write(c);
}
}
static void Main()
{
ReadOnlyMemory<char> name = "safe".AsMemory();
Print(name);
}
}
异步方法中的使用
Memory<T>可跨越await边界,而Span<T>不能。因此在异步读写流时,用Memory作为参数类型最安全。
using System;
using System.IO;
using System.Threading.Tasks;
class AsyncDemo
{
static async Task WriteAsync(Stream stream, Memory<byte> buffer)
{
await stream.WriteAsync(buffer);
}
static async Task Main()
{
byte[] bytes = { 1, 2, 3 };
Memory<byte> mem = bytes;
using var ms = new MemoryStream();
await WriteAsync(ms, mem);
}
}
对比与选择
| 类型 | 可读写 | 可跨异步 | 典型用途 |
|---|---|---|---|
| Span<T> | 是 | 否 | 同步局部内存处理 |
| Memory<T> | 是 | 是 | 异步或传递读写视图 |
| ReadOnlyMemory<T> | 否 | 是 | 传递只读数据片段 |
合理选用上述类型,可显著降低内存错误概率,同时维持高性能。优先用ReadOnlyMemory表达不变性,用Memory替代byte数组拷贝,是C#内存安全操作的通行做法。
C#MemoryReadOnlyMemory内存安全Span修改时间:2026-07-25 09:12:20