我如何将 map<string, int> 从 C++ 获取到 C#

How I can get map<string, int> from C++ to C#

我正在尝试从 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");

不幸的是,这个问题的简单答案是 "you shouldn't"。您不应该首先从 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# 代码。它应该只是将 "Test" 的值为 346 添加到字典中,仅此而已。它通过调用一个回调函数来做到这一点,该回调函数是 Dictionary.Add 周围的本机垫片,用于字典的指定实例。

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# 中禁用了 "Prefer 32-bit"。