【发布时间】: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 也会产生拳击垃圾;甚至是泛型重载。)