我仍在尝试找到一种快速的方法,该方法如何将TOutput类型的通用数组转换为TInput类型的另一个数组。我所有的数组始终都是数字数据类型,但是由于C#没有像经常要求的那样对Numeric进行类型约束,因此我目前必须忍受这种约束。建议的方法,就像之前转换到对象一样,似乎极大地减慢了我的转换速度。目前,我有一个大型的if/else构造,用于检查类型并使用指针算术将其强制转换为定义的类型,但这是将来处理大型代码的方法。 Parallel.For似乎是摆脱指针并加快速度的一种好方法,但是C#泛型约束似乎仍然是一个问题,但是下面代码中的Tout仍然是一个问题。这是我的代码:

    public static OutputType[] Cast<InputType, OutputType>(InputType[] inputArray_in)
    {
        var aRange = Partitioner.Create(0, inputArray_in.Length);
        OutputType[] aResult = new OutputType[inputArray_in.Length];

        Parallel.ForEach(aRange, (r) =>
        {
            for (int i = r.Item1; i < r.Item2; i++)
            {
                aResult[i] = (OutputType)(inputArray_in[i]);
            }
        });

        return aResult;
    }

例子:
float[] A = { 0.1f, 0.2f, 0.6f };
int []B = Cast<float, int>(A);

在所有情况下,我的数组类型都是数值(浮点型,短型, double 型……),并且在大多数情况下,数组的大小约为512x512,但堆栈中的体积约为1000个切片。
您是否有机会采用一种简单的方法来执行此操作?

测试代码
public static class CastTest
{
    delegate double[] CastMethod(int[] input);

    public static unsafe double[] Cast1(int[] input)
    {
        int N = input.Length;
        double[] output = new double[N];

        for (int i = 0; i < N; i++) output[i] = (double)(input[i]);

        return output;
    }

    public static unsafe double[] Cast2(int[] input)
    {
        int N = input.Length;
        double[] output = new double[N];

        fixed (double* output_pinned = output)
        {
            double* outp = output_pinned;

            fixed (int* input_pinned = input)
            {
                int* inp = input_pinned;

                for (int i = 0; i < N; i++, inp++, outp++) *outp = (double)(*inp);
            }

            return output;
        }
    }

    public static unsafe double[] Cast3(int[] input)
    {
        int N = input.Length;
        double[] output = new double[N];

        fixed (double* output_pinned = output)
        {
            double* outp = output_pinned;

            fixed (int* input_pinned = input)
            {
                int* inp = input_pinned;

                for (int i = 0; i < N; i++) outp[i] = (double)(inp[i]);
            }

            return output;
        }
    }

    public static unsafe double[] Cast4(int[] input)
    {
        int N = input.Length;
        double[] output = new double[N];

        fixed (double* output_pinned = output)
        {
            fixed (int* input_pinned = input)
            {
                for (int i = 0; i < N; i++) output_pinned[i] = (double)(input_pinned[i]);
            }
        }

        return output;
    }

    public static unsafe double[] Cast5(int[] input)
    {
        return Array.ConvertAll<int, double>(input, x => (double)x);
    }

    public static double[] Cast6(int[] input)
    {
        var aRange = Partitioner.Create(0, input.Length);

        int N = input.Length;
        double[] output = new double[N];

        Parallel.ForEach(aRange, (r) =>
            {
                for (int i = r.Item1; i < r.Item2; i++) output[i] = (double)(input[i]);
            });

        return output;
    }

    public unsafe static double[] Cast7(int[] input)
    {
        var aRange = Partitioner.Create(0, input.Length);

        int N = input.Length;
        double[] output = new double[N];

        Parallel.ForEach(aRange, (r) =>
        {
            fixed (double* output_pinned = output)
            {
                double* outp = output_pinned + r.Item1;

                fixed (int* input_pinned = input)
                {
                    int* inp = input_pinned + r.Item1;

                    for (int i = r.Item1; i < r.Item2; i++, outp++, inp++) *outp = (double)(*inp);
                }
            }
        });

        return output;
    }

    public unsafe static double[] Cast8(int[] input)
    {
        var result = (from m in input.AsParallel() select (double)m).ToArray();

        return result;
    }


    public static double[] Cast9(int[] input)
    {
        return  (from m in input select (double)m).ToArray();
    }

    public static double[] Cast10(int[] input)
    {
        return (from m in input.AsParallel() select (double)m).ToArray();
    }

    public static double[] Cast11(int[] input)
    {
        return new List<double>(input.Select(p => (double)p)).ToArray();
    }

    static int[] A = new int[100000];
    const int runs = 10000;

    public static void StartTest()
    {
        TestMethod("1", Cast1);
        TestMethod("2", Cast2);
        TestMethod("3", Cast3);
        TestMethod("4", Cast4);
        TestMethod("5", Cast5);
        TestMethod("6", Cast6);
        TestMethod("7", Cast7);
        TestMethod("8", Cast8);
        TestMethod("9", Cast9);
        TestMethod("10", Cast10);
        TestMethod("11", Cast11);
    }

    static void TestMethod(string Name, CastMethod method)
    {
        var timer = Stopwatch.StartNew();

        for (int i = 0; i < runs; i++) { double[] res = method(A); }

        timer.Stop();

        Console.WriteLine(String.Format("{0}: {1}ms", Name, timer.ElapsedMilliseconds));
    }
}

谢谢
马丁

最佳答案

像这样的数值类型之间没有魔术转换(使用泛型等时);有一些类似Convert.ChangeTypedynamic的技巧,但它们都涉及一个中间的box/unbox。

就个人而言,我只是在使用:

float[] A = { 0.1f, 0.2f, 0.6f };
int[] B = Array.ConvertAll(A, x => (int)x);

这将转换逻辑卸载到编译器中(以使用正确的从floatint的转换,而无需中介或反射)。但是,它在泛型内部不可用-即x => (OutputType)x将不起作用。

关于c# - 如何将泛型数组转换为另一种类型?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/9698023/

10-17 02:17