c#复制结构体数组到双精度体数组

本文关键字:数组 双精度 结构体 复制 | 更新日期: 2023-09-27 18:03:28

[StructLayout(LayoutKind.Sequential)]
public struct Demo
{
    double X;
    double Y;
}

var data = new Demo[128];
FillWithMeaningfulValues(data);
double[] doubles;
Copy(data, out doubles); // ?

如何将演示数组复制到双精度数组中,而不必通过每个元素for(…)?在c++中,我会使用memcpy,但在c#中,我没有在Marshal.Copy中找到我需要的东西。

void MethodIDoNotWantToUse(Demo[] demo, out double[] doubles)
{
    doubles = new double[demo.Length * 2];
    for(int i = 0, j = 0; i < demo.Length; ++i)
    {
        doubles[j++] = demo[i].X;
        doubles[j++] = demo[i].Y;
    }  
}
void MethodIWouldPreferToUse(Demo[] demo, out double[] doubles)
{
    doubles = new double[demo.Length * 2];
    memcopy(doubles, demo, demo.Length * 2 * sizeof(double));
}

c#复制结构体数组到双精度体数组

您将执行如下操作。Marshal.Copy do提供您所需要的。

Demo[] array = new Demo[2];
array[0] = new Demo {X = 5.6, Y= 6.6};
array[1] = new Demo {X = 7.6, Y = 8.6};
GCHandle handle = GCHandle.Alloc(array, GCHandleType.Pinned);
try
{
    IntPtr pointer = handle.AddrOfPinnedObject();
    double[] copy = new double[array.Length*2];//This length may be calculated
    Marshal.Copy(pointer, copy, 0, copy.Length);
}
finally
{
    if (handle.IsAllocated)
        handle.Free();
}

由于该结构体是可比特的,因此该结构体的数组也是可比特的。因此,可以用Marshal.Copy固定struct数组并将其复制到双精度数组中。

void CopyDemoArrayToDoubleArray(Demo[] demo, out double[] doubles)
{
    doubles = new double[demo.Length * 2];
    GCHandle gch = GCHandle.Alloc(demo, GCHandleType.Pinned);
    try
    {
        IntPtr demoPtr = gch.AddrOfPinnedObject();
        Marshal.Copy(demoPtr, doubles, 0, doubles.Length);
    }
    finally
    {
        gch.Free();
    }
}

您可以根据您想要避免的更简单的for循环对其进行基准测试。

for循环将完全充分地发挥作用是合理的。

可以编写一个泛型方法来转换任何兼容类型的数组(这里的"兼容"是指"元素必须是值类型,元素的大小必须兼容")。

你可以使用p/Invoke来调用Windows API的CopyMemory()方法。

但是,请记住,这样做可能没有任何性能优势;你应该仔细计时,以确保。

[DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);
public TOut[] ConvertArray<TIn, TOut>(TIn[] input) where TIn:struct where TOut:struct
{
    if (input == null)
        throw new ArgumentNullException("input");
    int sizeTIn   = Marshal.SizeOf(typeof(TIn));
    int sizeTOut  = Marshal.SizeOf(typeof(TOut));
    int sizeBytes = input.Length*sizeTIn;
    if ((sizeBytes % sizeTOut) != 0)
        throw new ArgumentException("Size of input type is not compatible with size of output type.");
    int sizeOut = sizeBytes/sizeTOut;
    var output = new TOut[sizeOut];
    GCHandle inHandle  = GCHandle.Alloc(input,  GCHandleType.Pinned);
    GCHandle outHandle = GCHandle.Alloc(output, GCHandleType.Pinned);
    try
    {
        IntPtr inPtr  = inHandle.AddrOfPinnedObject();
        IntPtr outPtr = outHandle.AddrOfPinnedObject();
        CopyMemory(outPtr, inPtr, (uint)sizeBytes);
    }
    finally
    {
        outHandle.Free();
        inHandle.Free();
    }
    return output;
}

对于您的示例,您可以这样调用:

Demo[] test = new Demo[10];
for (int i = 0; i < 10; ++i)
    test[i] = new Demo {X = i, Y = i};
var result = ConvertArray<Demo, double>(test);
for (int i = 0; i < 20; ++i)
    Console.WriteLine(result[i]);