使用 P/Invoke 时存储非托管代码的数据

Storing data for unmanaged code when using P/Invoke

我有一个此结构的数组(此处显示在 C# 中,但也存在于 C++ 中):

[StructLayout(LayoutKind.Sequential)]
public struct MyStruct
{
    IntPtr name;             //pointer to string, char* on C++ side

    long pValues;
    long jValues;
    long eValues;
    long kValues;

    int cost;
};

和 C++ DLL 中的一个算法,它确实在它上面工作,从托管 C# 代码调用。它是 CPU-heavy,这是必要的,因为它在 C++ 中的运行速度比 C# 快得多。托管 (C#) 端永远不必知道结构数据的内容,因为该算法仅 returns 单个整数数组。

那么,在应用程序的生命周期内,我将如何以最有效的方式(即开销最少)存储这些数据?我想我已经缩小到两个选项:

  1. 在 C# 中初始化结构和设置值,使用 GCHandle 固定内存并在我想工作时传递对 C++ 的引用(参见 Unity 论坛上的 this post

  2. 在 C++ 中初始化结构并设置值,使结构在非托管端持久保存在内存中

所以我的问题很具体:

对于 1,我对编组的工作方式感到困惑。在 MSDN: Copying and Pinning 中,您似乎可以通过固定和传递对固定数据的引用来传递结构数组,无需复制或转换任何数据(并且只要结构在两侧看起来相同)。我读得对吗,它实际上是这样工作的吗?参考Unity3d论坛post,我看到Marshal.PtrToStructure被调用;我认为执行复制操作?由于在这种情况下数据将存储在托管端,因此每次调用 C++ 函数时都必须复制 and/or 转换数据会导致大量开销,除非我认为这些类型的操作是比实际价格贵很多。

对于 2,我想知道是否可以在 C++ 调用之间保持持久性。据我所知,如果你是 P/Invoking 来自 DLL,你不能在非托管端拥有持久数据,所以我不能只在那里定义和存储我的结构数组,使唯一的数据在托管和非托管之间传输由非托管算法产生的 int 数组。这是正确的吗?

非常感谢您抽出宝贵时间阅读和帮助!

如果 C# 代码不需要了解数组和结构的内部结构,请不要将其暴露给 C# 代码。在非托管代码中完成此类型的所有工作并避免编组开销。

本质上,您想遵循这个基本模式。我敢肯定细节会有所不同,但这应该给你基本的概念。

C++

MyStruct* newArray(const int len)
{
    return new MyStruct[len];
}

void workOnArray(MyStruct* array, const int len)
{
    // do stuff with the array
}

void deleteArray(const MyStruct* array)
{
    delete[] array;
}

C#

[DllImport(dllname)]
static extern IntPtr newArray(int len);

[DllImport(dllname)]
static extern void workOnArray(IntPtr array int len);

[DllImport(dllname)]
static extern void deleteArray(IntPtr array);