将结构传递给 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 个步骤解决您的问题:
- 在 C++/CLI 中编写一个静态函数
getNodes()
,您可以像任何常规静态方法一样从 C# 调用它,将 string
作为参数传递。上面的文章将帮助你。在创建 C++/CLI 项目时也 See Here。
getNodes()
将使用您的 C++ 代码创建非托管形式的 tree
。
- 使用
getNodes()
将 tree
从非托管形式转换为托管形式。
- 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 倍。
我正在编写代码来解析 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 个步骤解决您的问题:
- 在 C++/CLI 中编写一个静态函数
getNodes()
,您可以像任何常规静态方法一样从 C# 调用它,将string
作为参数传递。上面的文章将帮助你。在创建 C++/CLI 项目时也 See Here。 getNodes()
将使用您的 C++ 代码创建非托管形式的tree
。- 使用
getNodes()
将tree
从非托管形式转换为托管形式。 - 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 倍。