C#编组C++结构继承

KOT*_*TIX 5 c# c++ inheritance struct marshalling

假设我在C++中有以下结构

struct Base
{
    USHORT  size;
}

struct Inherited : public Base
{
    BYTE    type;
}
Run Code Online (Sandbox Code Playgroud)

我想Inherited在C#中编组,但结构继承在C#中不起作用.正在做以下适当的事情吗?

public interface IBase
{
    ushort Size { get; set; }
}

[StructLayout(LayoutKind.Sequential)]
public struct Inherited : IBase
{
    public ushort Size { get; set; }
    public byte Type { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我在这里简化了问题,结构更大,难以验证结果.此外,结构来自另一个不太好的文档,使得验证结果更加困难.在C++中使用继承时,是子结构之前还是之后的基类字段?

我正在使用它IBase作为强制基本字段存在的方式.

不幸的是,我无法控制C++方面(我与之集成的外部系统的SDK).

Han*_*ant 3

“适当”一词并不完全适用于这些 C# 声明。到目前为止,避免事故的最佳方法是依赖属性和接口的实现细节。该结构应声明为内部结构并仅使用普通字段。

该代码片段没有演示故障模式,因此我必须假设它是确实存在问题的真实声明的简化版本。检查 C# 代码是否正确获得结构声明的方法是验证结构的大小和最后一个字段的偏移量在 C++ 和 C# 中是否相同。首先编写一个小测试程序来检查,此代码片段的 C++ 版本应如下所示:

#include <Windows.h>
#include <stddef.h>

struct Base {
    USHORT  size;
};

struct Inherited : public Base {
    BYTE    type;
};


int main()
{
    int len = sizeof(Inherited);
    int ofs = offsetof(Inherited, type);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

并使用调试器检查lenofs变量,在本例中为 4 和 2。在 C# 中执行完全相同的操作:

using System;
using System.Runtime.InteropServices;

class Program {
    static void Main(string[] args) {
        var len = Marshal.SizeOf(typeof(Inherited));
        var ofs = Marshal.OffsetOf(typeof(Inherited), "<Type>k__BackingField");
    }
}
public interface IBase {
    ushort Size { get; set; }
}

[StructLayout(LayoutKind.Sequential)]
public struct Inherited : IBase {
    public ushort Size { get; set; }
    public byte Type { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

还是4和2,所以完美匹配和pinvoke应该不错。当实际声明不匹配时,向后查看变量ofs,您会发现声明错误的成员。请注意使用该属性的后果,强制检查支持字段的不稳定名称。当使用字段而不是属性来声明结构体时,强烈建议使用此代码,这样代码会更简单。