2016-03-07 96 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