将结构传递给 C#
Posted
技术标签:
【中文标题】将结构传递给 C#【英文标题】:Passing Structure to C# 【发布时间】:2017-11-10 03:57:43 【问题描述】:我正在编写代码来解析 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
"
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
成员并复制每个参数。这是正确的方法吗?
【问题讨论】:
是的,您可以使用托管 C++,通过 COM 公开您的 C++ 方法,还有更多。 在C++中和在C#中具有相同的树结构有什么好处?这真的取决于这一切的用途。通常(尤其是当您拥有双方,托管和非托管时),您将一种语言用于使用/场景,您不需要用两种语言来做/编码所有事情。 @wp78de 我不知道有什么明确的好处,我只是不知道在 c# 中扩展了 c++ 中的数据结构。我的理解是,字符串向量必须在托管代码和非托管代码之间手动传输。 【参考方案1】:您可以按照您第一篇引用的文章使用 pInvoke,但您返回的对象似乎相当复杂。我认为,如果您还不精通(甚至那时),您将在数据编组方面度过一段愉快的时光。 pInvoke 非常适合对 C 库的简单调用,其中数据编组是基本的,但它很快就会变得非常复杂。这对你的情况不利。
第二篇文章更接近你想看的地方。话虽如此,您必须考虑是要包装托管类还是只调用一个接受字符串并以托管格式返回树的函数(即,它制作副本而不是包装非托管数据)。根据您的帖子,您似乎只需要后者。
您最好的选择是使用 C++/CLI。查看this tutorial。我相信采用这种方法将使您的任务变得轻松。我不会试图解释这个主题,因为上面的文章做得很好。从本质上讲,您将能够编写具有托管和非托管数据类型的函数,其中所有数据编组都内置在环境中。一个简单的演员将在幕后为您整理数据。作为一大好处,调试非常棒,因为您可以从 C# 到 C++/CLI 再到 C++ 代码并返回。
在上面的文章中,作者确实描述了如何包装一个非托管类,你可以做到,但你的问题仍然是数据转换。
我会分 4 步解决您的问题:
-
在 C++/CLI 中编写一个静态函数
getNodes()
,您可以将其作为任何常规静态方法从 C# 调用,并将 string
作为参数传递。上面的文章将帮助您。还有See Here 创建 C++/CLI 项目时。
getNodes()
将使用您的 C++ 代码以非托管形式创建 tree
。
使用getNodes()
将tree
从非托管形式转换为托管形式。
将结果返回给 C# 中的调用者。
您的声明将如下所示,其中Node
是您的托管类,ref
关键字表示该类是托管的,^
是*
的托管版本。
public ref class noderizer
public:
static Node^ getNodes(String ^mStr);
;
这里getNodes()
调用您的C++ 函数并进行数据转换。我认为你不会花很长时间才能弄清楚。
一旦掌握了语法,如果您已经熟悉 C# 和 C++,我想您会发现它使用起来非常直观。
至于性能,除非您连续拨打数千次电话或需要关键的实时数据,否则这应该不是问题。不过我要说的一件事是,如果您关心性能,您应该在单独的纯非托管 dll 中编写纯 C++ 代码。我一生都找不到这篇文章,但我记得查看了一些基准,即执行在 C++/CLI dll 中编译的纯非托管长时间运行代码块与调用在其内部编译的完全相同的代码非托管 dll。如果我没记错的话,单独的 dll 大约快 3 倍。
【讨论】:
以上是关于将结构传递给 C#的主要内容,如果未能解决你的问题,请参考以下文章