我正在编写代码以解析C++中的复杂字符串并从中创建树。我想在Visual Studio 2017中使用C#调用返回节点 vector 的本机c++方法。

一个节点看起来像:

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

和c++函数可能看起来像:
class noderizer
{
public:
    node getNodes(std::string str);
};

调用noderizer::getNodes(...)成员并为C#创建等效类的最有效的方式(编码时间,其次是速度)。

我假设最好的方法是在C#中创建一个重复的类定义,然后将本机std::strings编码为托管Strings
public class node
{
    public string  name = string.Empty;
    List<node> integers = new List<node>();
}

尚不清楚this article是否包含有关c++互操作的最新信息,但是有关在C#中使用的wrapping c++ native classes的相关文章指出,我很可能只将noderizer本机c++包装为noderizer * m_Impl;,然后调用getNodes成员并复制每个参数。这是正确的方法吗?

最佳答案

您可以按照第一篇引用的文章使用pInvoke,但是返回的对象似乎很复杂。我认为,如果您还不熟悉(甚至是不熟悉)数据的话,您将有一段时间。 pInvoke非常适合简单地调用C库,在C库中数据编码是基本的,但是它变得非常复杂。这对您的情况不利。

第二篇文章更靠近您想要看的地方。话虽如此,您必须考虑是要包装托管类还是只调用一个接受字符串并以托管格式返回树的函数(即,它进行复制而不是包装非托管数据)。在您的帖子看来,您只需要后者。

最好的选择是使用C++ / CLI。 checkout this tutorial。我相信采用这种方法将使您的工作轻而易举。我不会尝试解释这个主题,因为上面的文章做得很好。本质上,您将能够使用托管和非托管数据类型编写函数,其中所有数据编码都内置于环境中。一个简单的转换将在后台为您封送数据。作为一大好处,调试非常好,因为您可以从C#过渡到C++ / CLI再过渡到C++代码。

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

我将通过4个步骤解决您的问题:

  • 在C++ / CLI中编写一个静态函数getNodes(),您可以作为任何常规的静态方法从C#调用它,并将string作为参数传递。上面的文章将帮助您。创建C++ / CLI项目时,还需要See Here
  • getNodes()将使用您的C++代码以非托管形式创建tree
  • 使用getNodes()tree从非托管形式转换为托管形式。
  • 将结果返回给C#中的调用者。

  • 您的声明将类似于以下内容,其中Node是托管的calss,关键字ref表示该类是托管的,而^*的托管版本。
    public ref class noderizer
    {
    public:
        static Node^ getNodes(String ^mStr);
    };
    

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

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

    10-07 22:44