C# 封送LayoutKind.Explicit结构(具有重叠)在发布版本中失败

C# 封送LayoutKind.Explicit结构(具有重叠)在发布版本中失败,c#,marshalling,layoutkind.explicit,C#,Marshalling,Layoutkind.explicit,我有一个结构,它有一个报告为重叠的非重叠字段 [FieldOffset(8)] Int32 X; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] [FieldOffset(12)] string Y; [FieldOffset(28)] int Z; 报告的错误是: 无法加载类型“XXX”。。。它包含偏移12处的对象字段,该字段未正确对齐或被非对象字段重叠 它只出现在版本配置中(跟踪、调试标志和不安全代码被启用,优化被关闭),猜测-

我有一个结构,它有一个报告为重叠的非重叠字段

[FieldOffset(8)]
Int32 X;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
[FieldOffset(12)]
string Y;

[FieldOffset(28)]
int Z;
报告的错误是:

无法加载类型“XXX”。。。它包含偏移12处的对象字段,该字段未正确对齐或被非对象字段重叠

它只出现在版本配置中(跟踪、调试标志和不安全代码被启用,优化被关闭),猜测-它会发生什么


UPD:感谢@svick。确认x64版本不是编组所需的版本。

我认为系统中数据字段的默认对齐方式为8字节。您必须首先为Y使用偏移量16。

,发布配置与此无关。影响它的是平台目标:如果将其设置为x64,则会出现此异常,但如果将其设置为x86,则可以正常工作

我认为这种行为的原因是
FieldOffset
用于指定托管内存中
struct
的布局(即使文档没有这样说),但
MarshalAs
不用于托管内存

因此,托管内存中的对象在偏移量12处包含一个引用。由于所有引用都必须在.Net中对齐(32位应用程序中为4字节,64位应用程序中为8字节),因此如果您以64位运行应用程序,则会出现异常

因此,问题不在于字段重叠,而是错误消息的另一部分:字段对齐不正确


简单的解决方法是将应用程序编译为x86。如果这对您来说不可能,我不知道如何解决这个问题。

注释@svick的正确答案,这里的问题是您的结构声明违反了CLR使对象分配是原子的硬承诺。这无法在64位模式下工作,偏移量为12时,对象指针可以跨越缓存线的末端。访问这样一个未对齐的成员总是需要两次读取或写入,这永远不会是原子的。我认为这实际上是CLR类型验证程序中的一个bug,但这并不能帮助您克服这个困难

当然,您这样做是为了与32位代码进行互操作,并且您正确地更改了调试版本的平台目标设置,但忘记了对发布版本进行设置。这是一个每配置设置。轻松修复,只需更改发布配置的设置即可


如果您真的需要它在64位模式下工作,那么您需要将其声明为
固定字符[16]

是否在StructLayout属性中指定字符集?比如说?如果不是,我想可能会在构建之间出现一些奇怪的字符集切换,因为这种结构可以正确使用单字节字符,但不能使用宽字符扫描您使用
LayoutKind.Sequential
而不是
LayoutKind.Explicit
,并删除
FieldOffset
属性?这并不总是可能的,但如果在这种情况下对您来说是可能的,它可能会避免整个问题。