如何从 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[] keysint[] 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++ 中的 <map> 的 C# 等价物是啥? [复制]

将浮点数组从 C++ 获取到 C#

如何从 C# 中的 C++ dll 中的全局变量从函数中获取返回数组?

如何从 C# 中的通用 List<T> 中获取元素? [复制]

从具有自定义类型的 c++ 中的 std::map 获取值

C++ 函数到 C#