【问题标题】:How to cast an array of structures (of double values) to an array of double values如何将结构数组(双值)转换为双值数组
【发布时间】:2017-10-22 19:48:37
【问题描述】:

我正在尝试创建一个包装器来将 System.Numeric.Complex 数组视为双精度数组,即将{{1,2},{3,4},{5,6},{7,8} 视为{1,2,3,4,5,6,7,8}。我将这些数组用于 FFT,因此这种方式会更有效,因为可以避免复制和迭代巨大的数组。但是我遇到了一个奇怪的嵌合怪物:A Double array object of kind double[] {System.Numerics.Complex[4],而不是 double[8]!!。那是什么?

我不是互操作专家,所以请原谅任何重要的错误;我读了一些相关的东西herehere,我想知道这些数组是否重叠。 Τ他的代码几乎可以工作,只是它返回了一半的值:

 //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)

    }

【问题讨论】:

  • 你声明了一个联合。 C# 不直接支持,因为它们是众所周知的类型不安全,但它不会阻止您使用这些 CLR 属性。您设法很好地重叠了数组元素,但您不能避开存储长度的字段。它是 4,而不是 8。您唯一能做的就是编写真正不安全的代码并使用指针,这样就不会有任何边界检查。使用 fixed 关键字获取 Complex* 并使用 (double*) 进行转换。

标签: c# .net arrays interop field


【解决方案1】:

您希望数组只存储双精度数。但它们也存储数组长度和对类型描述符的引用。因此,您重叠两种 .NET 类型的方法不起作用。 C# 不是 C。

DoubleComplexChimeraMonster 静态类型为double[],但GetType() 检索运行时类型,恰好是Complex[]

相同内存位置的重叠值适用于原始值类型。但是System.Array 是一个类。

正如 Marc Gravell 在您提供的链接的 answer 中所说,不安全的指针可能是要走的路。

【讨论】:

  • 是的,我展示了它,但我想在 VB 应用程序中使用它,所以我也想保证它的安全......不受指针影响。
  • Interop 用于 COM 和 .NET 应用程序之间的互操作。它不是 C# 中经常使用的功能,并且不比不安全指针更好。
猜你喜欢
  • 2015-09-13
  • 2017-02-24
  • 2020-08-03
  • 1970-01-01
  • 1970-01-01
  • 2021-10-18
  • 2017-12-17
  • 2011-07-07
  • 1970-01-01
相关资源
最近更新 更多