2016-03-07 76 views
0

我有一个由第三方库提供的托管数组。数组的类型并不直接反映数组中存储的数据,而是将数据解释为整数。将托管数组无法复制到结构数组中

所以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

即使在C中,这样的构造也是UB(其中原始副本也取决于实现)。你可以想象在一个强大的类型系统的托管世界... –

+1

@kasperhj你确定它会导致性能问题吗?你真的需要[使其更快](http://ericlippert.com/2012/12/17/performance-rant/)?也许你可以要求第三方从他们的方法中提供更强的类型数据?在最坏的情况下,你可能会尝试使用不安全的代码(它应该允许做这样的事情),但是在做之前你应该考虑两次。 –

+0

@EugenePodskal在我的应用程序中没有任何性能问题,但只是为了改变解释而进行了很多复制。 – kasperhj

回答

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(如果它是1 2字节),或者你不需要任何东西(请参阅解释(1)后)

我会补充说,这种技术是无证的,完全不安全。它甚至有一个问题:ds.Length不是DataStructure[]的长度,而是int[]的长度(所以在给定的例子中是8,而不是2)

“技术”与我描述的相同here,最初描述为here

说明(1)

sizeof(double)是8个字节,所以Value通常的8个字节的边界上对齐,所以通常存在 “间隙” Id(具有sizeof(int) == 4)和4个Value之间字节。所以通常是sizeof(DataStructure) == 16。取决于DataStructure的构建方式,不可能有这种差距,因此Pack = 4强制在4字节边界上对齐。

+0

虽然我真的不愿意在我的生产代码中实现这一点,但它似乎确实有用。由于似乎没有其他方式获得相同的结果,这就是答案。谢谢。 – kasperhj

+1

@kasperhj为此,有一个解决方案...(即使您想使用反射也应该应用的解决方案)在程序开始时进行一些“完整性检查”:测试结构的副本如何工作应该。这样就不会有任何“隐藏的问题”。就像在开始时执行的单元测试一样。 – xanatos

相关问题