您可以使用固定数组Marshal.UnsafeAddrOfPinnedArrayElement
中的 an 来获取数组中特定元素的地址。IntPtr
这是一个围绕固定数组的包装器的示例类,以便我可以将它们与 IntPtr 和编组代码一起使用:
/// <summary>
/// Pins an array of Blittable structs so that we can access the data as bytes. Manages a GCHandle around the array.
/// https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.marshal.unsafeaddrofpinnedarrayelement?view=netframework-4.7.2
/// </summary>
public sealed class PinnedArray<T> : IDisposable
{
public GCHandle Handle { get; }
public T[] Array { get; }
public int ByteCount { get; private set; }
public IntPtr Ptr { get; private set; }
public IntPtr ElementPointer(int n)
{
return Marshal.UnsafeAddrOfPinnedArrayElement(Array, n);
}
public PinnedArray(T[] xs)
{
Array = xs;
// This will fail if the underlying type is not Blittable (e.g. not contiguous in memory)
Handle = GCHandle.Alloc(xs, GCHandleType.Pinned);
if (xs.Length != 0)
{
Ptr = ElementPointer(0);
ByteCount = (int) Ptr.Distance(ElementPointer(Array.Length));
}
else
{
Ptr = IntPtr.Zero;
ByteCount = 0;
}
}
void DisposeImplementation()
{
if (Ptr != IntPtr.Zero)
{
Handle.Free();
Ptr = IntPtr.Zero;
ByteCount = 0;
}
}
~PinnedArray()
{
DisposeImplementation();
}
public void Dispose()
{
DisposeImplementation();
GC.SuppressFinalize(this);
}
}
恕我直言,使用 PInvoke 和 IntPtr 就像将程序集标记为不安全并在不安全的上下文中使用指针一样危险(如果不是更多的话)
如果您不介意不安全的块,您可以编写对IntPtr
强制转换进行操作的扩展函数,byte*
如下所示:
public static long Distance(this IntPtr a, IntPtr b)
{
return Math.Abs(((byte*)b) - ((byte*)a));
}
但是,像往常一样,您必须注意在转换为不同的指针类型时可能出现的对齐问题。