MarshalAs 是不是会导致数组副本?
Posted
技术标签:
【中文标题】MarshalAs 是不是会导致数组副本?【英文标题】:Does MarshalAs result in an array copy?MarshalAs 是否会导致数组副本? 【发布时间】:2019-01-04 22:19:56 【问题描述】:我有一个项目可以处理相当大的数组。有些代码是用 C 编写的,有些是用 C# 编写的。要将数据从 C 传递到 C#,我使用了 MarshalAs
属性。由于数组很大,我宁愿避免复制。所以我的问题是:MarshalAs
会导致数据从 C 复制到 C#,还是 C# byte[]
会引用 C 分配的完全相同的位置?
C 函数负责将数据传递给 C#,这意味着我使用回调。回调如下所示:
void (*to_call)(const uint8_t* buffer, int buffer_length);
DLLEXPORT
init(void(*callback)(const uint8_t* buffer, int buffer_length))
to_call = callback;
最终,to_call
回调将从 C 中调用。C# 代码如下所示:
public delegate void Callback([In][MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]byte[] buffer, int bufferLength);
[DllImport(DLLPath)]
public static extern void init(Callback callback);
我也想知道答案如何适用于 .Net Framework 和 .Net Core。
【问题讨论】:
我手头没有 Adam Nathan 的“.NET 和 COM”一书,但如果我没记错的话,“视情况而定”。同样,如果我记得(大约十年前),这取决于这两种表示是否是各向同性的(即,它们以相同的方式适合相同的位)。从 .NETbyte[]
转到非托管代码时,它可能会起作用。相反的方向(我很确定)不起作用。 .NET 数组是以特定方式布局的托管对象。我大约 99% 确定您不能从非托管的字节集合中构建 byte[]
。新的Span
功能可能会有所帮助??
您可以通过在托管内存 (C#) 中分配所有结构、固定它们并将指针传递给非托管代码来避免复制。 Rick Brewster 做了a good write-up (with code) 详细说明了他是如何在paint.net 中做到这一点的;还有see this article除此之外,您可能还想查看Memory Mapped files。
你是打算在 C# 中使用这些数组还是只是传递它们?如果您只是传递它们,您可以使用 IntPtr(对于 uint8_t*)。请注意,您还可以在需要时从 IntPtr 读取并复制它指向 byte[] 的位置。
【参考方案1】:
根据Does .NET interop copy array data back and forth, or does it pin the array?,它应该被固定。
虽然这似乎并没有很好的记录或定义,但如果我是你,我会明确地固定它,以确保安全。
【讨论】:
以上是关于MarshalAs 是不是会导致数组副本?的主要内容,如果未能解决你的问题,请参考以下文章
我是不是需要在 C# 中使用来自非托管 C++ dll 的原始数据类型执行 MarshalAs?
J Link 未出现在 Eclipse Mars 菜单中(非副本)