2016-01-22 17 views
1

的字段的對象包含在.net中以便將它的數據複製到字節數組中。爲了牽制和應對我用下面的代碼:GCHandle。如何將包含字段定義爲類

C c = new C(); 
byte[] b = new byte[Marshal.SizeOf(c)]; 
GCHandle gch = GCHandle.Alloc(c, GCHandleType.Pinned); 
Marshal.Copy(gch.AddrOfPinnedObject(), b, 0, b.Length); 
gch.Free(); 

當我宣佈我的對象定義爲便接踵而來:

[StructLayout(LayoutKind.Sequential, Pack = 1)] 
struct A 
{ 
    public int a; 
} 
[StructLayout(LayoutKind.Sequential, Pack = 1)] 
struct C 
{ 
    public A a0; 
    public A a1; 
    public A a2; 
} 

所有做工精細。當我聲明我的對象定義如下:

[StructLayout(LayoutKind.Sequential, Pack = 1)] 
struct A 
{ 
    public int a; 
} 
[StructLayout(LayoutKind.Sequential, Pack = 1)] 
class C 
{ 
    public A a0; 
    public A a1; 
    public A a2; 
} 

也都工作正常。但是,當我我的兩個對象聲明爲:「對象包含非基本或非blittable數據」

[StructLayout(LayoutKind.Sequential, Pack = 1)] 
class A 
{ 
    public int a; 
} 
[StructLayout(LayoutKind.Sequential, Pack = 1)] 
class C 
{ 
    public A a0; 
    public A a1; 
    public A a2; 
} 

則引發ArgumentException在GCHandle.Alloc(...)

爲什麼當A被定義爲struct時一切正常。但是,當班級不工作?可以將這兩種類型A和C都定義爲類來工作嗎?

+0

[This](http://stackoverflow.com/questions/15544818/non-blitable-error-on-a-blitable-type)可能有幫助 –

回答

3

您正試圖擊敗垃圾回收器,您正在將引用複製到類對象中,成爲GC無法看到的內存塊。這是無效的,這樣的參考價值在短短的納秒後變成垃圾。每當GC運行時,您都不知道何時。 GC不能更新參考,它不知道它存在。

這樣做只有當這些引用指向的對象不能被垃圾回收並且無法移動時才能正確執行。換句話說,他們必須被釘住。你說服編組人員,你可能得到這個正確的:

[StructLayout(LayoutKind.Sequential, Pack = 1)] 
class C 
{ 
    public IntPtr a0; 
    public IntPtr a1; 
    public IntPtr a2; 
} 

你已經知道如何獲得這些IntPtr值。有了額外的規定,而不是由CLR檢查,只要其他代碼可能使用內存斑點,就讓這些對象保持固定。

+0

但是當我聲明一個類C爲你建議我不能創建字節[]在我的代碼示例中。 Marshal.SizeOf爲你的類C返回12或24(32或64位)和Marshal.Copy複製到byte []不是來自A類成員的數據,而是將IntPtr值分割爲字節? –

+0

12是正確的,32位模式下的3個對象引用需要3 x 4 = 12個字節。在64位模式下3 x 8 = 24個字節。當然它不復製成員,它複製參考。如果你想複製成員,那麼你必須聲明它爲* struct *。避免問一個XY問題,沒人知道你爲什麼要這樣做。 –

相關問題