2010-03-05 91 views
7
“联盟”型阅读C结构

我想带来托管方(C#)建于C.从C#与PInvoke的

结构

假设这种结构(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 ST与联合体域一ructure类型A)

[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框架正在承担TypeC,因为这是最后申报的。我还注意到,如果TypeC的尺寸小于TypeA,则无法读取所有的TypeA字段。

这是一个来自.net的错误还是我应该做一些不同的事情?

回答

7

问题是关于使用引用类型来包装非托管类型。 当CLR执行“GetType”方法时,它使用一个虚拟表,它只能包含一个在声明中被连续覆盖的类型。最后声明的字段获胜(TypeC在这种情况下)
将“类”切换为“结构”可以解决问题。

[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 
{ 
    //... 
}