C#如何从ushort[]的任意位置获取byte[]且不复制数据
在C#中从ushort[]任意位置获取无复制的byte[]
我有一个长度为7的ushort[]示例:
var ushorts = new ushort[7] {1, 2, 3, 4, 5, 6, 7};
它在内存中占用14个连续字节:
01 00 02 00 03 00 04 00 05 00 06 00 07 00
需要从这14个字节的中间任意位置获取一个byte[],且不复制数据。类似C++中通过指针重定向实现的无复制操作:
#include <iostream> typedef unsigned short ushort; typedef unsigned char byte; int main() { ushort* ushorts = new ushort[7] {1, 2, 3, 4, 5, 6, 7}; byte* bytes = reinterpret_cast<byte*>(&(ushorts[2])); for (int i = 0; i < 8; i++) { std::cout << (int)bytes[i] << ' '; } // stdout: 3 0 4 0 5 0 6 0 std::cout << std::endl; delete ushorts; return 0; }
方案1:使用Span或Memory(推荐,无unsafe代码)
在.NET Core 2.1+、.NET 5+或.NET Standard 2.1+环境下,可借助Span<T>和Memory<T>实现无复制的内存视图操作,无需unsafe权限:
var ushorts = new ushort[7] {1, 2, 3, 4, 5, 6, 7}; // 将ushort[]直接映射为字节视图,无数据复制 Span<byte> allBytes = MemoryMarshal.AsBytes(ushorts.AsSpan()); // 从第4个字节(对应ushorts[2]的起始位置)截取8个字节的视图 Span<byte> targetBytes = allBytes.Slice(start: 4, length: 8); // 若需用于异步场景或保存持久引用,可转为Memory<byte> Memory<byte> targetMemory = targetBytes; // 验证输出 foreach (byte b in targetBytes) { Console.Write($"{b} "); } // 输出:3 0 4 0 5 0 6 0
- 核心逻辑:
MemoryMarshal.AsBytes直接把原数组的内存区域映射为字节视图,Slice仅创建指向原内存片段的新视图,全程无数据复制。 - 注意:原生
byte[]是独立托管内存块,无法直接让它指向另一个数组的内存片段。如果业务场景可以接受用Span<byte>/Memory<byte>替代byte[],这是最优解;若必须要byte[],则只能通过ToArray()复制数据,但这不符合无复制要求。
方案2:使用unsafe代码(模拟C++指针逻辑)
如果是.NET Framework环境或必须用指针操作,可开启unsafe代码实现:
unsafe { var ushorts = new ushort[7] {1, 2, 3, 4, 5, 6, 7}; fixed (ushort* ushortPtr = &ushorts[2]) { byte* bytePtr = (byte*)ushortPtr; // 直接操作指针访问原内存 for (int i = 0; i < 8; i++) { Console.Write($"{bytePtr[i]} "); } // 输出:3 0 4 0 5 0 6 0 } }
- 核心逻辑:
fixed关键字固定数组内存防止GC移动,通过指针类型转换直接访问原数组的字节区域,无数据复制。 - 注意:需在项目设置中开启“允许不安全代码”选项才能编译运行。
内容的提问来源于stack exchange,提问作者beauxq
相关产品推荐
相关产品推荐

