我正在尝试创建多个结构的联合。我遇到一个包含另一个结构数组的结构的问题。
[StructLayout(LayoutKind.Explicit)]
public struct FruitBasket
{
[MarshalAs(UnmanagedType.Struct)]
[FieldOffset(0)]
public Apples Apple;
[FieldOffset(0)]
public Grapes Grape;
[FieldOffset(0)]
public Oranges Orange;
}
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi, Size = 12)]
public struct Apples
{
public int Color;
public int Texture;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 15)]
public Types[] Type;
}
如果我单独使用苹果结构,编组工作正常。但是,如果我尝试做类似的事情;
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi]
public class Buffet
{
public UInt32 NumMeats;
public UInt32 NumVeggies;
public FruitBasket NumFruits; //public Apples Apple; <-- works fine
}
我收到以下错误;
FruitBasket'来自程序集'Test,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null',因为它包含偏移0处的对象字段,该字段被非对象字段错误地对齐或重叠。
答案 0 :(得分:0)
问题是数组是一种引用类型(MarshalAs
没有改变它 - 它只适用于执行pinvoke时)。这意味着在结构中有一个引用到其他地方的数组。在您的情况下,存储该引用的内存位置与union中的其他内容共享,这可能无法正常工作。
所以你需要的是在结构中使用那个数组,如果使用不安全的代码,那就是possible。问题是:
唯一的限制是数组类型必须是bool,byte,char,short,int,long,sbyte,ushort,uint,ulong,float或double。
因此,您拥有Types
- 它不是一个选项。但如果可以将其更改为其中一种受支持的类型,则可以这样做:
public unsafe struct Apples
{
public int Color;
public int Texture;
public fixed int Type[15];
}
编辑:是的,正如@IllidanS4所提到的 - 如果你需要使用除这些类型之外的任何东西(结构),你可以手动添加这15个字段,逐个。不是很整洁......
编辑2:第二个选项是同时跳过联合 - 制作三个单独的结构并让编组人员使用Marshal.PtrToStructure
为您排序。在这种情况下,MarshalAs
将适用于数组,避免使用fixed
。但是你必须做三次,但这可能是一个更实用的选择。
答案 1 :(得分:0)
MarshalAs
与FieldOffset
或StructLayout
有很大不同。 MarshalAs
只是一个“普通”参数,它向Marshaller指示如何编组字段,它修改了结构的非托管布局。另一方面,当您在C#中使用它时,FieldOffset
直接修改结构的托管布局。 MarshalAs
对托管环境中的结构布局没有影响。因此,它不会使Types
固定大小的值数组,因此CLR仍会抱怨引用与某个值重叠(包含在同一偏移量的其他结构中)。
对于原始类型,您可以使用fixed
,但我担心它不适用于Type
。我想,你可以为“数组”的每个元素创建一个包含15个物理字段的结构。不要忘记它仅在Types
是结构(或枚举)而不是引用时才有效。
尽管如此,这通常不是常见问题的解决方案,只能在P / Invoke中使用。