【问题标题】:How can I pin (and get an IntPtr to) a generic T[] array?如何固定(并获取 IntPtr 到)通用 T[] 数组?
【发布时间】:2016-05-31 20:49:13
【问题描述】:

我想固定一个通用类型的数组并获得一个指向其内存的指针:

T[] arr = ...;
fixed (T* ptr = arr)
{
    // Use ptr here.
}

但是尝试编译上面的代码会产生这个编译器错误:

Cannot take the address of, get the size of, or declare a pointer to a managed type

thesequestions 的答案确认无法声明通用的T* 指针。但是有没有办法固定一个通用的T[] 数组并将IntPtr 固定到固定的内存? (这样的指针仍然有用,因为它可以传递给本机代码或强制转换为已知类型的指针。)

【问题讨论】:

  • 这个问题会让很多 C# 程序员陷入困境。 IntPtr 和 T* 之间有很大的区别。不,您不能盲目地将 IntPtr 传递给本机代码,它可能会遭受与您的 C# 程序相同的命运。但无一例外地警告你。非平凡的 T 类型需要被编组,以便它们的布局被很好地定义并且成员类型转换得到照顾。 Marshal.StructureToPtr() 执行此操作。在 pinvoke 声明中使用 T[] 始终是最佳选择,既安全尽可能快。
  • @HansPassant - 这些是需要牢记的好点,并且在可能的情况下绝对应该更喜欢使用标准的编组功能。但在某些情况下,你别无选择。例如,当调用采用 void* 指针的本机 API 时(因为 API 可以采用任意格式的数据),因此 pinvoke 编组不会为您处理这些问题。我个人通过 SharpDX .Net 包装器使用 DirectX 进行了很多工作,这很多
  • 此外,在某些情况下,出于性能原因(免责声明:配置文件以在使用此类不安全代码之前识别性能瓶颈),您希望获取指向数组的指针并复制其全部内容立即指向目标指针。理论上可以对数组的每个元素调用 StructureToPtr,但这比简单地复制整个数组要昂贵得多。 (而且 StructureToPtr 也会产生拳击垃圾;甚至是泛型重载。)

标签: c# .net


【解决方案1】:

是的,您可以使用 GCHandle 对象固定一个通用的 T[] 数组,并在固定时将一个 IntPtr 放入其内存中:

T[] arr = ...;
GCHandle handle = GCHandle.Alloc(arr, GCHandleType.Pinned);
IntPtr ptr = handle.AddrOfPinnedObject();
// Use the ptr.
handle.Free();

确保你记得调用Free(),否则数组将永远不会被取消固定。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-08
    • 1970-01-01
    • 2022-11-29
    • 2023-03-06
    • 2015-01-25
    • 2020-06-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多