将结构传递给 C#

Passing Structure to C#

我正在编写代码来解析 C++ 中的复杂字符串并从中创建树。我想在 Visual Studio 2017 年使用 C# 调用本机 c++ 方法,该方法 returns 节点向量。

一个节点看起来像:

class node
{
  public:
    std::vector<node> subnodes;
    std::string name;
};

c++ 函数可能如下所示:

class noderizer
{
public:
    node getNodes(std::string str);
};

调用 noderizer::getNodes(...) 成员并为 c# 创建等效 class 的最有效方法(编码时间,次要考虑速度)是什么?

我假设最好的方法是在 c# 中创建一个重复的 class 定义,然后将本机 std::strings 编组复制到托管 Strings"

public class node
{
    public string  name = string.Empty;
    List<node> integers = new List<node>();
}

不清楚 this article contains the latest information for c++ interop, but a related article on wrapping c++ native classes 在 c# 中的使用是否表明我很可能只是将 noderizer 原生 c++ 包装为 noderizer * m_Impl; 然后调用 getNodes 成员和复制每个参数。这是正确的方法吗?

您可以按照您引用的第一篇文章使用 pInvoke,但您返回的对象似乎相当复杂。我认为如果您还不精通数据编组(甚至那时),您将会花很多时间进行数据编组。 pInvoke 非常适合简单地调用 C 库,其中数据编组是基本的,但它很快就会变得非常复杂。这对你的情况不利。

第二篇更接近你想看的地方。话虽如此,您必须考虑是要包装一个托管 class 还是只调用一个函数,该函数接受一个字符串和 returns 您的树以托管格式(即它制作一个副本而不是包装非托管数据)。根据你的 post 看来你只需要后者。

您最好的选择是使用 C++/CLI。查看 this tutorial。我相信采用这种方法将使您轻松完成任务。我不会尝试解释这个主题,因为上面的文章做得很好。本质上,您将能够使用托管和非托管数据类型编写函数,其中所有数据编组都内置到环境中。一个简单的转换将在幕后为您整理数据。作为一个很大的好处,调试非常棒,因为您可以从 C# 到 C++/CLI 再到 C++ 代码并返回。

在上面的文章中,作者确实描述了如何包装一个非托管的 class,您可以很好地做到这一点,但是您的问题仍然在于数据转换。

我会分 4 个步骤解决您的问题:

  1. 在 C++/CLI 中编写一个静态函数 getNodes(),您可以像任何常规静态方法一样从 C# 调用它,将 string 作为参数传递。上面的文章将帮助你。在创建 C++/CLI 项目时也 See Here
  2. getNodes() 将使用您的 C++ 代码创建非托管形式的 tree
  3. 使用 getNodes()tree 从非托管形式转换为托管形式。
  4. Return C# 调用者的结果。

你的声明看起来像这样,其中 Node 是你的托管类,ref 关键字表示 class 是托管的,^*.

的托管版本
public ref class noderizer
{
public:
    static Node^ getNodes(String ^mStr);
};

这里 getNodes() 调用您的 C++ 函数并进行数据转换。我不认为你会花很长时间来弄明白。 一旦掌握了语法,如果您已经熟悉 C# 和 C++,我想您会发现它的使用非常直观。

至于性能,除非您要进行数千次连续调用或需要关键的实时数据,否则这应该不是问题。不过我要说的一件事是,如果您关心性能,则应该在单独的纯非托管 dll 中编写纯 C++ 代码。我一生都找不到这篇文章,但我记得看过一些基准测试,执行在 C++/CLI dll 中编译的纯非托管长 运行 代码块与调用完全相同的已编译代码在它自己的纯非托管 dll 中。如果我没记错的话,单独的 dll 大约快 3 倍。