.NET 8手动编组结构体固定偏移字节数组触发异常如何解决?
问题解决思路与修正代码
错误根源
你碰到的System.TypeLoadException本质原因是:byte[]是托管引用类型,在结构体中存储的是指向数组数据的指针(64位系统占8字节)。CLR对引用类型字段有两个强制要求:
- 必须满足平台对齐规则(64位系统下是8字节对齐),偏移2显然不符合;
- 引用类型字段的内存区域不能与值类型字段重叠,而你的
valueArray指针会覆盖后续valueC的内存位置。
Pack=1只影响非托管值类型的对齐,对托管引用类型的指针无效,所以靠调整Pack无法解决问题。
修正方案:使用固定大小缓冲区(Fixed Buffer)
固定大小缓冲区是值类型,会直接嵌入结构体的内存布局中,不需要指针,完全适配显式布局的要求。需要开启项目的不安全代码支持(项目属性→生成→勾选“允许不安全代码”)。
基础版结构体修正代码
[StructLayout(LayoutKind.Explicit, Size = 257, Pack = 1)] public unsafe struct MyFrame { [FieldOffset(0)] public byte valueA; [FieldOffset(1)] public byte valueB; [FieldOffset(2)] public fixed byte valueArray[254]; [FieldOffset(256)] public byte valueC; }
联合版结构体修正代码
注意:原代码中Size=258是错误的,rawBytes长度257字节刚好覆盖整个结构体(偏移0到256),所以结构体总大小应为257:
[StructLayout(LayoutKind.Explicit, Size = 257, Pack = 1)] public unsafe struct MyFrame { [FieldOffset(0)] public byte valueA; [FieldOffset(1)] public byte valueB; [FieldOffset(2)] public fixed byte valueArray[254]; [FieldOffset(256)] public byte valueC; [FieldOffset(0)] public fixed byte rawBytes[257]; }
固定缓冲区的操作方法
如果需要将固定缓冲区转换为更易用的Span<byte>或byte[],可以借助MemoryMarshal:
var frame = new MyFrame(); // 将valueArray转为Span<byte> unsafe { Span<byte> arraySpan = MemoryMarshal.CreateSpan(ref frame.valueArray[0], 254); // 直接操作arraySpan即可修改结构体内存 } // 将rawBytes转为Span<byte> unsafe { Span<byte> rawSpan = MemoryMarshal.CreateSpan(ref frame.rawBytes[0], 257); }
内容的提问来源于stack exchange,提问作者Axel M
相关产品推荐
相关产品推荐

