0

I am trying to create a wrapper to treat System.Numeric.Complex array as array of double, i.e. to treat {{1,2},{3,4},{5,6},{7,8} as {1,2,3,4,5,6,7,8}. I use these arrays for FFT so this way will be more efficient because avoids copying and iterating huge arrays. But i stuck on a strange chimeric monster: A Double array object of kind double[] {System.Numerics.Complex[4], instead of double[8]!!. What's that?

I am not an interop expert so excuse any essential blunder; I read some related stuff here and here and I wonder if the case is that these arrays are overlapped. Τhis code almost works except for that it returns half of the values:

 //using System.Runtime.InteropServices;
 //using System.Numeric;

    [StructLayout(LayoutKind.Explicit)]
    public struct ComplexArray2serialWrapper
    {
        [FieldOffset(0)] private Complex[] ComplexArray;
        [FieldOffset(0)] private double[] DoubleArray;

        public ComplexArray2serialWrapper(Complex[] NewcomplexArray) : this() { ComplexArray = NewcomplexArray; }
        public ComplexArray2serialWrapper(double[] NewSerialComplexArray) : this() { DoubleArray = NewSerialComplexArray; }
        public static implicit operator double[] (ComplexArray2serialWrapper source) { return source.DoubleArray; }
    }


    public static void TestWrapper()
    {
        Complex[] cc = { new Complex(1, 2), new Complex(3, 4), new Complex(5, 6), new Complex(7, 8) };  
        double[] DoubleComplexChimeraMonster = new ComplexArray2serialWrapper(cc);
        var parenttype = DoubleComplexChimeraMonster.GetType(); // result = System.Numerics.Complex[]
        //!!! but in watch window type shown as=  double[] {System.Numerics.Complex[4]}

        var ChildrenType = DoubleComplexChimeraMonster[0].GetType(); //System.Double
        //In Watch window, children types shown chimeric:        
        //{ (1, 2)} Double {System.Numerics.Complex} 
        //{ (3, 4)} Double {System.Numerics.Complex} 
        //{ (5, 6)} Double {System.Numerics.Complex} 
        //{ (7, 8)} Double {System.Numerics.Complex}

        double i1 = DoubleComplexChimeraMonster[0]; //=1 (as expected)
        double i2 = DoubleComplexChimeraMonster[1]; //=2 (as expected)
        double i3 = DoubleComplexChimeraMonster[2]; //=3 (as expected)
        double i4 = DoubleComplexChimeraMonster[3]; //=4 (as expected)
        var l = DoubleComplexChimeraMonster.Length; //=4 (8 expected)


        //So trying to get i5-i8 will throw an exception e.g.:
        //DoubleComplexChimeraMonster(4)  --> exception (5 expected)

    }
anefeletos
  • 672
  • 7
  • 19
  • 1
    You declared a *union*. Not directly supported by C# because they are so notoriously type-unsafe but it won't stop you from using these CLR attributes. You managed to overlap the array elements just fine but you can't duck the field that stores the Length. It is 4, not 8. Only other thing you can do is write truly unsafe code and use a pointer so there won't be any bounds checks. Use the `fixed` keyword to get a Complex* and cast it with (double*). – Hans Passant Oct 23 '17 at 13:26

1 Answers1

1

You expect the arrays to store only the doubles. But they also store the array length and a reference to a type descriptor. Therefore, your approach of overlapping two .NET types does not work. C# is not C.

DoubleComplexChimeraMonster is statically typed as double[], however GetType() retrieves the runtime type, which happens to be Complex[].

Overlapping values at the same memory location works for primitive value types. But System.Array is a class.

As Marc Gravell says in this answer of the link you provided, unsafe pointers might be the way to go.

Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188