Маршаллинг массив структур против классов - PullRequest
4 голосов
/ 27 марта 2012

Я хочу прочитать нативную структуру в тип C #, используя Marshalling. Мой метод к структурам маршала такой:

T ReadObject<T>(BinaryReader br) {
    var bytes = br.ReadBytes(Marshal.SizeOf(typeof(T)));
    var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
    try {
        return (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
    }
    finally {
        handle.Free();
    }
}

Теперь это работает нормально, проблема возникает со следующим типом:

[StructLayout(LayoutKind.Sequential, Pack=1)]
class SubData {
    public short A1;
    public short A2;
}

[StructLayout(LayoutKind.Sequential, Pack=1)]
class Data {
    public short Id;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=3)]
    public SubData[] SubDatas;
}

Обратите внимание, что это прекрасно работает, если SubData является структурой ! Но если SubData является классом, он заставляет Marshal.PtrToStructure выдавать FatalExecutionEngineError. Я хотел бы придерживаться классов, потому что иногда мои типы имеют значения по умолчанию, а структуры не могут иметь инициализаторы полей или конструкторы по умолчанию, а также некоторые из этих типов довольно велики.

Спасибо за помощь.

Редактировать: сообщение об ошибке: «Во время выполнения обнаружена фатальная ошибка. Адрес ошибки был 0x6af99aec, в потоке 0x348. Код ошибки: 0xc0000005. Эта ошибка может быть ошибкой в ​​CLR или в небезопасном или не поддающиеся проверке части пользовательского кода. Общие источники этой ошибки включают ошибки пользовательского маршалинга для COM-взаимодействия или PInvoke, которые могут повредить стек. "

1 Ответ

1 голос
/ 27 марта 2012

Класс является ссылочным типом, поэтому при использовании Marshal.PtrToStructure он будет копировать указатель, а не значения в позиции подданных.
При объявлении Subdata в качестве struct, будут скопированы фактические значения subdata.
Таким образом, при выполнении Marshalling вы должны использовать struct. У вас все еще может быть класс, который будет принимать версию struct в конструкторе.
Например, вы можете доказать это с помощью

SizeOf

чтобы увидеть, что размеры будут отличаться.

...