我有第三方库提供的托管数组。数组的类型不直接反映存储在数组中的数据,而是将数据解释为整数。
所以int[] data = Lib.GetData();
给了我一个整数数组,我希望将其转换为DataStructure
的数组,它看起来像这样。
struct DataStructure {
public int Id;
public double Value;
}
当前我使用Marshal.Copy
(可以看到here的实现),但复制整个内容似乎有些过分。
这样的事情是否存在:
int[] data = Lib.GetData();
DataStructure[] dataStructs = InterpretAs<DataStructure>(data);
不需要复制,但可以像dataStruct
那样访问dataStruct[1].Id
元素吗?
编辑2:
如果我只想要一个DataStructure
,我可以使用
public static T ToStruct<T>(byte[] bytes) where T : struct
{
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
T something = Marshal.PtrToStructure<T>(handle.AddrOfPinnedObject());
handle.Free();
return something;
}
不需要复制。
修改
可能重复的答案目前大约有7年的历史,它们包括复制数据或实施黑客攻击。
答案 0 :(得分:2)
实际上有作弊,但它是丑陋 不安全 完全不安全作弊:
[StructLayout(LayoutKind.Sequential)]
//[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct DataStructure
{
public int Id;
public double Value;
}
[StructLayout(LayoutKind.Explicit)]
public struct DataStructureConverter
{
[FieldOffset(0)]
public int[] IntArray;
[FieldOffset(0)]
public DataStructure[] DataStructureArray;
}
然后你可以毫无问题地转换它:
var myarray = new int[8];
myarray[0] = 1;
myarray[3] = 2;
//myarray[4] = 2;
DataStructure[] ds = new DataStructureConverter { IntArray = myarray }.DataStructureArray;
int i1 = ds[0].Id;
int i2 = ds[1].Id;
请注意,根据DataStructure
的大小(如果是16个字节或12个字节),您必须使用Pack = 4
(如果它是12个字节)或者您不需要任何内容(稍后参见说明(1)
我要补充一点,这种技术没有记录,完全不安全。它甚至有一个问题:ds.Length不是DataStructure[]
的长度,而是int[]
的长度(所以在给定的例子中它是8,而不是2)
解释(1)
sizeof(double)
是8个字节,因此Value
通常在8字节边界上对齐,所以通常Id
之间存在“间隙”(sizeof(int) == 4
)和4个字节的Value
。通常是sizeof(DataStructure) == 16
。根据DataStructure的构建方式,不会出现这种差距,因此Pack = 4
强制对齐4字节边界。