2016-01-22 1 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(); 

И когда я объявляю мои определения объектов, как Folow:

[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 определен как структура, все работает нормально. Но когда класс не работает? Можно ли выполнить эту работу с обоими типами 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 копирует в байты [] не данные из членов класса A, а значения IntPtr разделяются на байты? –

+0

12 правильно, 3 ссылки на объекты в 32-битном режиме требуют 3 x 4 = 12 байтов. И 3 x 8 = 24 байта в 64-битном режиме. И, конечно, он не копирует членов, он копирует ссылку. Если вы хотите также скопировать участников, вы должны объявить его как * struct *. Избегайте задавать вопрос XY, никто не знает, почему вы пытаетесь это сделать. –

 Смежные вопросы

  • Нет связанных вопросов^_^