gpt4 book ai didi

C#:将泛型指针转换为数组

转载 作者:行者123 更新时间:2023-11-30 20:14:04 32 4
gpt4 key购买 nike

我想将 byte* 转换为 byte[],但我也希望有一个可重用的函数来执行此操作:

public unsafe static T[] Create<T>(T* ptr, int length)
{
T[] array = new T[length];

for (int i = 0; i < length; i++)
array[i] = ptr[i];

return array;
}

不幸的是,我得到一个编译器错误,因为 T 可能是“.NET 托管类型”,我们不能有指向那些的指针。更令人沮丧的是,没有可以将 T 限制为“非托管类型”的泛型类型约束。是否有内置的 .NET 函数来执行此操作?有什么想法吗?

最佳答案

可以匹配您尝试执行的操作的方法是 Marshal.Copy , 但它没有采用适当的参数来制作通用方法。

虽然不可能编写具有通用约束的通用方法来描述可能的情况,但并不是每种类型都可以使用“不安全”的方式进行复制。有一些异常(exception);类就是其中之一。

这是一个示例代码:

    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 的类型.这在您的情况下可能不是问题,但如果指针数据来自 native C 或 C++ 代码,则指定布局类型很重要(CLR 可能会选择重新排序字段以获得更好的内存对齐)。

但是如果指针完全来自托管代码生成的数据,那么您可以删除检查。

此外,如果性能是个问题,有比逐字节复制数据更好的算法。 (引用memcpy的无数实现)

关于C#:将泛型指针转换为数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/985646/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com