选项 1 - 致电CopyMemory:
[DllImport("kernel32.dll", SetLastError = false)]
static extern void CopyMemory(IntPtr destination, IntPtr source, UIntPtr length);
public static void Copy<T>(IntPtr source, T[] destination, int startIndex, int length)
where T : struct
{
var gch = GCHandle.Alloc(destination, GCHandleType.Pinned);
try
{
var targetPtr = Marshal.UnsafeAddrOfPinnedArrayElement(destination, startIndex);
var bytesToCopy = Marshal.SizeOf(typeof(T)) * length;
CopyMemory(targetPtr, source, (UIntPtr)bytesToCopy);
}
finally
{
gch.Free();
}
}
不便携,但性能不错。
选项 2 - unsafe 和指针:
public static void Copy(IntPtr source, ushort[] destination, int startIndex, int length)
{
unsafe
{
var sourcePtr = (ushort*)source;
for(int i = startIndex; i < startIndex + length; ++i)
{
destination[i] = *sourcePtr++;
}
}
}
需要在项目构建属性中启用unsafe 选项。
选项 3 - 反射(只是为了好玩,不要在生产中使用):
Marshal 类在内部对所有 Copy(IntPtr, <array>, int, int) 重载使用 CopyToManaged(IntPtr, object, int, int) 方法(至少在 .NET 4.5 中)。使用反射我们可以直接调用该方法:
private static readonly Action<IntPtr, object, int, int> _copyToManaged =
GetCopyToManagedMethod();
private static Action<IntPtr, object, int, int> GetCopyToManagedMethod()
{
var method = typeof(Marshal).GetMethod("CopyToManaged",
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
return (Action<IntPtr, object, int, int>)method.CreateDelegate(
typeof(Action<IntPtr, object, int, int>), null);
}
public static void Copy<T>(IntPtr source, T[] destination, int startIndex, int length)
where T : struct
{
_copyToManaged(source, destination, startIndex, length);
}
由于Marshal 类内部结构可以更改,因此此方法不可靠且不应使用,尽管此实现可能最接近其他Marshal.Copy() 方法重载。