将结构传递给C#

时间:2017-11-10 03:57:43

标签: c# c++ .net pinvoke

我正在编写代码来解析C ++中的复杂字符串并从中创建一个树。我想在Visual Studio 2017中使用C#来调用返回节点向量的本机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&#34;

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

不清楚this article是否包含c ++互操作的最新信息,但是在wrapping c++ native classes上用于c#的相关文章表明我很可能只是换noderizer将原生c ++称为noderizer * m_Impl;,然后调用getNodes成员并复制每个参数。这是正确的方法吗?

1 个答案:

答案 0 :(得分:2)

您可以根据您的第一篇文章使用pInvoke,但您返回的对象看起来相当复杂。如果你还没精通(甚至那时),我想你会对数据编组有一点时间。 pInvoke很适合简单调用C库,其中数据编组是基本的,但它非常快速地变得非常复杂。这对你的情况不利。

第二篇文章更接近你想看的地方。话虽这么说,你必须考虑是否要包装托管类或只是调用一个带有字符串的函数并以托管格式返回你的树(即它创建一个副本而不是包装非托管数据)。通过你的帖子,你似乎只需要后者。

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

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

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

  1. 在C ++ / CLI中编写一个静态函数getNodes(),您可以从C#调用任何常规静态方法,并将string作为参数传递。上面的文章将帮助你。创建C ++ / CLI项目时也See Here
  2. getNodes()将使用您的C ++代码以非托管形式创建tree
  3. 使用getNodes()tree从非托管转换为托管表单。
  4. 将结果返回给C#中的调用者。
  5. 您的声明将如下所示,其中Node是您的托管密码,ref关键字表示该类已被管理,^是{{1}的托管版本}}

    *

    这里public ref class noderizer { public: static Node^ getNodes(String ^mStr); }; 调用您的C ++函数并进行数据转换。我认为你不会花很长时间才弄明白。 一旦掌握了语法,我认为如果你已经熟悉C#和C ++,你会发现它非常直观。

    至于性能,除非您要进行数千次连续呼叫或需要关键的实时数据,否则它应该不是问题。但有一点我会说,如果你关心性能,你应该在一个单独的纯粹非托管dll中编写纯C ++代码。我找不到关于我生活的文章,但我记得看过一些执行完全无管理的长时间运行的代码块的基准测试,这些代码块是在C ++ / CLI dll中编译的,并且调用完全相同的代码,这些代码完全是在它自己内部编译的unmanaged dll。如果我没记错的话,单独的dll就会快3倍。