[英]C# Unions of Structs that Contain Arrays of Structs
我正在嘗試創建多個結構的聯合。 我遇到一個包含另一個結構數組的結構的問題。
[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;
}
如果僅使用Apple結構,則封送處理效果很好。 但是,如果我嘗試做類似的事情;
[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
}
我收到以下錯誤;
程序集'Test,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null'中的FruitBasket',因為它包含偏移量為0的對象字段,該對象字段錯誤地與非對象字段對齊或重疊。
問題是數組是引用類型( MarshalAs
不會更改它-僅在執行pinvoke時適用)。 這意味着在結構中存在對其他地方的數組的引用。 而且,在您的情況下,存儲該引用的內存位置與聯合中的其他內容共享,這實際上是行不通的。
因此,您需要的是在struct中包含該數組,如果使用不安全的代碼,則可能是這樣 。 要注意的是:
唯一的限制是數組類型必須為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
使用Marshal.PtrToStructure
為您解決。 在這種情況下, MarshalAs
將適用於該數組,避免使用fixed
。 雖然您將必須執行三遍,但這可能是一種更實際的選擇。
MarshalAs
與FieldOffset
或StructLayout
不同。 MarshalAs
只是一個“常規”參數,向Marshaller指示如何封送字段,它修改了結構的非托管布局。 另一方面,當在C#中使用FieldOffset
直接修改結構的托管布局。 MarshalAs
對托管環境中的結構布局沒有影響。 因此,它不會使Types
固定大小的值數組,因此CLR仍然會抱怨引用被一個值覆蓋(包含在另一個偏移量相同的結構中)。
對於原始類型,您可以使用fixed
,但是恐怕它不適用於Type
。 我想,您剩下的就是為“數組”的每個元素創建一個具有15個物理字段的結構。 不要忘記,它僅在Types
是一個結構(或枚舉)而不是引用時才有效。
盡管如此,僅在P / Invoke中,這通常不是解決常見問題的方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.