我正在尝试将用 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();
在 main 函数的某个地方,我这样做:
S s = getUnionStruct();
Console.WriteLine("unions type: {0}",(S.a).GetType());
结果是“AssemblyName.Type C”(???)
.net Framework 采用 TypeC,因为它是最后声明的。我还注意到,如果 TypeC 的大小小于 TypeA,我将无法读取所有 TypeA 字段。
这是 .net 的错误还是我应该做一些不同的事情?
问题在于使用引用类型来包装非托管类型。
当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
{
//...
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)