Я пытаюсь принести к управляемой стороне (C#) структуру, созданную в C.
Давайте примем эту структуру (C код):
typedef struct S{
int i;
union{
TypeA a;
TypeB b;
TypeC c;
}uni;
} S;
Теперь, я создаю классы обертки C#:
[StructLayout(LayoutKind.Explicit)]
public class S
{
[FieldOffset(0)]
public int i;
[FieldOffset(4)]
public TypeA a;
[FieldOffset(4)]
public TypeB b;
[FieldOffset(4)]
public TypeC c;
}
И у меня есть метод PInvoke для получения объекта S:
(Реализация C создает и возвращает структуру S с TypeA в поле объединения),
[DllImport("Library.dll", CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.S)]
public static extern S getUnionStruct();
Где-нибудь в основной функции, я делаю:
S s = getUnionStruct();
Console.WriteLine("unions type: {0}",(S.a).GetType());
Результатом является "AssembleName. TypeC" (???)
.net Framework принимает TypeC, потому что это было объявленным последним. Я также замечаю, что, если размер TypeC меньше, чем TypeA, я становлюсь не могущим считать все поля TypeA..
Действительно ли это - ошибка от .NET, или я должен делать что-то другое?
Проблема заключается в использовании ссылочных типов для обертывания неуправляемых типов. {{1 }} Когда CLR выполняет метод "GetType", он использует виртуальную таблицу, которая может содержать только один тип, который был последовательно переопределен в объявлении. Побеждает последнее объявленное поле (в данном случае TypeC)
Переключение "class" на "struct" решает проблему.
[StructLayout(LayoutKind.Explicit)]
public struct S
{
[FieldOffset(0)]
public int i;
[FieldOffset(4)]
public TypeA a;
[FieldOffset(4)]
public TypeB b;
[FieldOffset(4)]
public TypeC c;
}
[StructLayout(LayoutKind.Sequencial)]
public struct TypeA
{
//...
}
[StructLayout(LayoutKind.Sequencial)]
public struct TypeB
{
//...
}
[StructLayout(LayoutKind.Sequencial)]
public struct TypeC
{
//...
}