如何从 C++ 到 C# 获取 map<string, int>
Posted
技术标签:
【中文标题】如何从 C++ 到 C# 获取 map<string, int>【英文标题】:How I can get map<string, int> from C++ to C# 【发布时间】:2018-10-30 12:22:33 【问题描述】:我正在尝试从 dll c++ 获取地图 所以我必须在 C# 端获取地图并将其解析为字典。 我已尝试执行以下步骤,但没有成功。
C++ 代码:
extern "C" __declspec(dllexport) map<string, int> createMap(string &fileName)
ifstream infile(fileName);
vector<string> bitsLine;
bool headerEnded = false;
string line;
int i = 0;
int length = 0;
while (getline(infile, line))
if (headerEnded)
bitsLine = split(line, ',');
signalsMap.insert( bitsLine.at(0), length );
else
if (line.find("HEADER_END") != std::string::npos)
headerEnded = true;
length = infile.tellg();
i++;
return signalsMap;
C#代码:
Dictionary<string, int> x = createMap("C:/users/asalah/source/repos/WindowsFormsApp3/WindowsFormsApp3/RR_Test2_3.csv");
【问题讨论】:
C# 不是 C++,它只是一种“脚本语言”,其中脚本是字节码(这里称为 CLI“公共语言中间体”),如 Java。因此,它 (C#) 无法理解像map
这样的原生类型,您必须使用 Platform Invoke 或类似的东西对其进行编组。
即使调用代码是 C++ 也很可能会失败,更不用说 C#了。了解std::map
的实现方式可能不同,或者内部结构不同,具体取决于编译器、编译器选项。此外,堆分配成为模块之间的问题等。
Dictionary
不是一个结构,而是一个类。您无法使用 dllimport 生成它。考虑使用可以传递的string[] keys
和int[] values
创建一个结构,并在调用后在c# 代码中从该结构创建一个字典。
@user9335240 C# 不是脚本语言,字节码也不是 C#。事实上,你可以在没有字节码的情况下编译 C# 程序。
@Ameer 许多可能的解决方案。在您了解如何序列化映射之前,C# 代码有许多不同的需求来使用 C++ DLL。这使得这个问题对 SO 来说太宽泛了。
【参考方案1】:
不幸的是,这个问题的简单答案是“你不应该”。首先,您不应该从 dll 中导出 STL 类型,更不用说尝试在 C# 中编组它们了。 STL 类型的内存布局可能因编译器而异,C++ 运行时因 C++ 运行时而异。它可能导致非常脆弱的代码。因此,如果您导出 C 函数,它应该使用 const char*
而不是 std::string
。
您可以做的就是在每个键和值可用时对其进行编组。这样做的好处是您不必对内存管理做任何工作,而且很容易集成到您已有的东西中,尽管我没有就性能发表任何声明。
如果对您有任何帮助,这里有一个简短的 C++ 和 C# 示例,可以帮助您继续这样的解决方案:
extern "C" __declspec(dllexport) void doFoo(void(*adder)(const char*, int32_t))
adder("Test", 346);
以下是使用此 API 的 C# 代码。它应该只是将值为 346 的“测试”添加到字典中,仅此而已。它通过调用一个回调函数来做到这一点,该函数是 Dictionary.Add 为字典的指定实例提供的原生 shim。
namespace Eff3
using System.Collections.Generic;
using System.Runtime.InteropServices;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void DictionaryAdd(string key, int value);
class Program
[DllImport("TestDll", CallingConvention = CallingConvention.Cdecl)]
static extern void doFoo(DictionaryAdd callback);
static void Main()
var result = new Dictionary<string, int>();
doFoo(result.Add);
我已经在我的机器上对此进行了测试,并在 x64 的 Visual C++ 2017 中构建了 DLL,并在 C# 中禁用了“首选 32 位”。
【讨论】:
工作,谢谢以上是关于如何从 C++ 到 C# 获取 map<string, int>的主要内容,如果未能解决你的问题,请参考以下文章
如何从 C# 中的 C++ dll 中的全局变量从函数中获取返回数组?