当将一个类从 c# 编组到本机 c++ 时,它会克隆吗?

Posted

技术标签:

【中文标题】当将一个类从 c# 编组到本机 c++ 时,它会克隆吗?【英文标题】:When marshalling a class from c# to native c++ does it clone? 【发布时间】:2015-11-19 23:49:05 【问题描述】:

如果我有类似的 c# 代码

[DllImport("SomeDll")]
private static extern void passAClass(ClassType myClass);

然后这样称呼它

ClassType myClass = new ClassType();
passAClass(myClass);

我可以看到类(它的数据段)作为指针传递给 dll,但我不确定运行时是否将类数据从其位置复制到新内存中,然后将指针传递给该新内存,或者如果它直接传递一个指向类的内存位置的指针。

我可以看到,如果 dll 更改内存中的数据,它会收到一个指针,该指针在调用后在 c# 中是可见的,但这可能是因为它会将另一个内存副本返回到托管类的位置已存储。

【问题讨论】:

认为当你编组实例时,它只是传递了足够的信息来显示对象应该如何交互以及它的结构是什么样的 - 数据 + 元数据 + 位置定义。基于此,我相信除了如何处理数据的结构之外,传递的实际对象只是一个引用,因此远程所做的更改确实会更改对象的数据。不是 100%。 指向类的实例。请小心,因为该类可能包含指向实际数据的指针。例如,类中的数组是一个指针,点的大小可能会根据数组是本地的还是全局的而有所不同。该数组应设为静态,以便 dll 可以访问它。 【参考方案1】:

但这可能是因为它又做了另一个内存副本

不,这不是自动的,您必须明确地为参数提供 [Out] 属性以确保它复制回来。您确实看到没有属性的更改返回的事实证明该类是blittable。换句话说,类的字段都是简单的值类型,它们没有被 CLR 重新排列。因此托管布局与非托管布局相同,允许 pinvoke marshaller 固定对象并传递指针。

这并不罕见。最好不要让它成为意外,例如,当您将本机代码移植到 x64 时,您可能会在下雨天失去一天的生活。为类提供 [StructLayout] 属性以确保顺序布局是个好主意。

【讨论】:

我应该提到,在实际使用中我 do 使用 structLayout 顺序(尽管我认为它实际上是默认值?)我读了你的答案,确认副本不是为简单类型制作,所以如果传递的类是一个巨大的数组,它只会固定它并传递指针,而不是昂贵地复制数组两次?非 blittable 参数的情况是什么?一个类 c1 引用了另一个类 c2,然后只传递 c1 的数据,包含指向 c2 的无用指针?

以上是关于当将一个类从 c# 编组到本机 c++ 时,它会克隆吗?的主要内容,如果未能解决你的问题,请参考以下文章

在 c# 中将 uchar[] 从本机 dll 编组为 byte[] 的正确方法

从 C++ 编组到 C# 时 CLR 崩溃

如何将 C++ 本机对象编组到托管 C++ CLI

直接将 C++ 浮点数组成员编组到 C#,无需复制

将字符串从 c# 编组到 c++

将 C++ 结构编组到 C# 类时出现 AccessViolationException