c# - 将 C++ float 组成员直接编码到 c# 而无需复制

标签 c# c++ marshalling

我有一个矩阵类,其中包含一个固定大小的 float 组,我想在 C# 包装器类中直接公开它:

class Matrix
{
public:
    float data[16];
    ...
};

通常,在 C# 中包装此结构时,我会将包装类型定义为 POD 结构,该结构将利用 [StructLayout(LayoutKind.Sequential)] 并允许我直接将类编码到和来自 C++/C#。但是,c++ 类公开了其他类型(通过成员或函数),这些类型无法以这种方式编码,因此我不得不使用 PIMPL 机制,其中我的 C# 类包含指向底层 C++ 结构的不透明指针 (IntPtr)。但是,我仍然想直接将c++ 结构的底层data 成员暴露给C# 对象。所谓直接,是指对 C# 中 data 元素的修改将直接反射(reflect)在底层 C++ 结构中(即 C# 成员不能是 C++ 成员的拷贝)。我的想法是像这样在 C# 中公开 data 成员:

public class Matrix
{
    protected HandleRef cptr; // opaque reference to equivalent C++ instance
    public float [] data
    {
        get
        {
            return Get_data(cptr);
        }
    }

    [DllImport(MY_CPP_DLL, EntryPoint = "CSharp_Get_data", CharSet = CHARSET)]
    [return: MarshalAs(UnmanagedType.LPArray, SizeConst = 16, ArraySubType = UnmanagedType.R4)]
    private static extern float [] Get_Data(HandleRef in_object);
};

我的 C++ dll 包含函数 CSharp_Get_data,如下所示:

DLLEXPORT float * STDCALL CSharp_Get_data(Matrix *obj)
{
    return obj->data;
}

这在 C++ 和 C# 中都编译得很好,但是当我尝试在 C# 中做这样的事情时:

Matrix asdf = new Matrix();
asdf.data[0] = 2.0f;

我收到一个 System.Runtime.InteropServices.MarshalDirectiveException,它指出 附加信息:无法编码(marshal)“返回值”:无效的托管/非托管类型组合。

有没有一种方法我可以使用这种方法而不遇到这个错误?我知道这是一个非常奇怪的用例,但我觉得这种方法似乎没有违反 MS 在此处描述的任何编码标准:https://learn.microsoft.com/en-us/dotnet/framework/interop/default-marshaling-for-arrays .

感谢您的帮助。

最佳答案

你无法获得 float[]除非.NET 分配内存。 StructLayout(Sequential) 也是如此, 也是——固定大小的缓冲区,例如 float[16]float[] 不兼容.

但是,如果您更想要方便和高效,您可以做什么 float[] , 是使用新的零拷贝缓冲类型。你可以构造一个 System.Span<float>从指向第一个元素的指针加上元素的数量,然后下标该跨度将使您可以直接访问内存。需要进行一些重构,但由于 Span<T>一旦重写代码以使用 Span,就可以同样很好地访问 .NET 数组,它可以存在于两个世界中(C# 和 C++ 分配的数据)。

关于c# - 将 C++ float 组成员直接编码到 c# 而无需复制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52414217/

相关文章:

c++ - 导出的 DLL 函数未按词法排序?

.net - 在 C++/CLI 中将 std::vector<>::iterator 转换为 .NET 接口(interface)

c# - ASP.NET MVC : Access Data in Controller from another controller

c# - 端点不可用时 UdpClient 不会失败

c++ - 带参数和数组的对象

c++ - 智能指针的意外行为

C# 将 SecureString 安全地转换为 UTF-8 byte[]

java - Jaxb 应该编码内部类吗?

c# - 在 C# 中构建文件路径的最佳实践

c# - GameObject 被哪个脚本销毁