的方法,可以匹配你正在試圖做的是Marshal.Copy,但它不採取適當的參數來制定一個通用的方法。
雖然在那裏不可能編寫一個泛型約束的通用方法來描述什麼是可能的,但並不是每個類型都可以使用「不安全」方式進行復制。有一些例外;類是其中之一。
下面是一個示例代碼:
public unsafe static T[] Create<T>(void* source, int length)
{
var type = typeof(T);
var sizeInBytes = Marshal.SizeOf(typeof(T));
T[] output = new T[length];
if (type.IsPrimitive)
{
// Make sure the array won't be moved around by the GC
var handle = GCHandle.Alloc(output, GCHandleType.Pinned);
var destination = (byte*)handle.AddrOfPinnedObject().ToPointer();
var byteLength = length * sizeInBytes;
// There are faster ways to do this, particularly by using wider types or by
// handling special lengths.
for (int i = 0; i < byteLength; i++)
destination[i] = ((byte*)source)[i];
handle.Free();
}
else if (type.IsValueType)
{
if (!type.IsLayoutSequential && !type.IsExplicitLayout)
{
throw new InvalidOperationException(string.Format("{0} does not define a StructLayout attribute", type));
}
IntPtr sourcePtr = new IntPtr(source);
for (int i = 0; i < length; i++)
{
IntPtr p = new IntPtr((byte*)source + i * sizeInBytes);
output[i] = (T)System.Runtime.InteropServices.Marshal.PtrToStructure(p, typeof(T));
}
}
else
{
throw new InvalidOperationException(string.Format("{0} is not supported", type));
}
return output;
}
unsafe static void Main(string[] args)
{
var arrayDouble = Enumerable.Range(1, 1024)
.Select(i => (double)i)
.ToArray();
fixed (double* p = arrayDouble)
{
var array2 = Create<double>(p, arrayDouble.Length);
Assert.AreEqual(arrayDouble, array2);
}
var arrayPoint = Enumerable.Range(1, 1024)
.Select(i => new Point(i, i * 2 + 1))
.ToArray();
fixed (Point* p = arrayPoint)
{
var array2 = Create<Point>(p, arrayPoint.Length);
Assert.AreEqual(arrayPoint, array2);
}
}
方法可以是通用的,但它不能採取一般類型的指針。這不是問題,因爲指針協變是有幫助的,但是這具有阻止泛型參數類型的隱式解析的不良效果。然後您必須明確指定MakeArray。
我已經爲結構添加了一個特殊情況,最好是指定struct layout的類型。這可能不是問題,但如果指針數據來自本機C或C++代碼,指定佈局類型很重要(CLR可能會選擇重新排列字段以獲得更好的內存對齊)。
但是,如果指針完全來自託管代碼生成的數據,那麼您可以刪除該檢查。另外,如果性能是一個問題,那麼複製數據的算法比逐字節地執行要好。 (請參閱memcpy的無數實現以供參考)
這不起作用,因爲T可能不是結構體 - 字節,int,long等。 – wj32 2009-06-12 09:04:06
看起來很接近但我看不到指針正在遞增 - 它將始終使用第一個字節。另外,是否有無效的原因*? – 2009-06-12 09:05:40