为何C#认为该非托管结构体存在字段重叠?
问题原因与解决方案
错误根源
你遇到的TypeLoadException核心原因是:byte[]是引用类型(托管对象),即使添加了MarshalAs属性,该属性仅作用于非托管代码的封送逻辑,不会改变它在托管内存中的存储形式。
在托管内存里,byte[]本质是一个指针(64位系统占8字节,32位系统占4字节),而非你预期的13字节数组内容。你通过FieldOffset(4)指定它的起始位置,再加上指针自身的字节数,会直接和后续的transmissionNumber(FieldOffset(17))字段产生内存重叠,同时CLR对引用类型字段有严格的对齐要求,这就触发了类型加载错误。
两种可行解决方案
方案1:使用unsafe固定数组(推荐用于严格匹配非托管内存布局)
将byte[]替换为fixed字节数组,这样数组内容会直接嵌入结构体的内存中,完全符合你预期的18字节布局:
[StructLayout(LayoutKind.Explicit, Size = 18, Pack = 1, CharSet = CharSet.Ansi)] unsafe struct FlexTransmission { [FieldOffset(0)] public UInt32 transmissionTime; [FieldOffset(4)] public fixed byte flexData[13]; // 直接嵌入结构体的13字节连续内存 [FieldOffset(17)] public byte transmissionNumber; }
注意:需要在项目属性的「生成」选项中勾选允许不安全代码才能编译。
方案2:改用顺序布局(无需unsafe代码)
如果不需要显式指定FieldOffset,改用LayoutKind.Sequential,配合MarshalAs确保互操作时的封送正确性:
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi, Size = 18)] struct FlexTransmission { public UInt32 transmissionTime; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 13)] public byte[] flexData; public byte transmissionNumber; }
这种方式下,托管内存中flexData仍是引用类型,但在与非托管代码交互时,CLR会按照你指定的13字节数组进行封送,不会触发类型加载错误。
内容的提问来源于stack exchange,提问作者erict
相关产品推荐
相关产品推荐

