【问题标题】:Is is possible to convert C# double[,,] array to double[] without making a copy是否可以将 C# double[,,] 数组转换为 double[] 而无需复制
【发布时间】:2010-09-10 21:31:23
【问题描述】:

我的 .NET 应用程序中有大量的 3D 数字数组。我需要将它们转换为一维数组以将其传递给 COM 库。有没有办法在不复制所有数据的情况下转换数组?

我可以像这样进行转换,但是我使用了两倍的内存量,这在我的应用程序中是一个问题:

  double[] result = new double[input.GetLength(0) * input.GetLength(1) * input.GetLength(2)];
  for (i = 0; i < input.GetLength(0); i++) 
    for (j = 0; j < input.GetLength(1); j++) 
      for (k = 0; k < input.GetLength(2); k++) 
        result[i * input.GetLength(1) * input.GetLength(2) + j * input.GetLength(2) + k)] = input[i,j,l];
  return result;

【问题讨论】:

    标签: c# .net arrays


    【解决方案1】:

    我不相信 C# 将数据存储在内存中的方式会像在 C 中的简单强制转换那样可行。为什么不使用 1d 数组开始并为该类型创建一个类,以便您可以在程序中访问它,就像它是 3d 数组一样?

    【讨论】:

      【解决方案2】:

      不幸的是,C# 数组不能保证在连续内存中,就像在 C 等更接近金属的语言中一样。所以,不。如果没有逐个元素的复制,就无法将 double[,,] 转换为 double[]。

      【讨论】:

        【解决方案3】:

        考虑使用Proxy 抽象对数据的访问(类似于C++ 中的迭代器/智能指针)。不幸的是,语法不如 C++ 干净,因为 operator() 不能用于重载,并且 operator[] 是单参数,但仍然很接近。

        当然,这种额外的抽象级别增加了复杂性和它自己的工作,但它允许您对使用 double[,,] 对象的现有代码进行最小的更改,同时允许您使用单个 double[]用于互操作和 in-C# 计算的数组。

        class Matrix3
        {
            // referece-to-element object
            public struct Matrix3Elem{
                private Matrix3Impl impl;
                private uint dim0, dim1, dim2;
                // other constructors
                Matrix3Elem(Matrix3Impl impl_, uint dim0_, uint dim1_, uint dim2_) {
                    impl = impl_; dim0 = dim0_; dim1 = dim1_; dim2 = dim2_;
                }
                public double Value{
                    get { return impl.GetAt(dim0,dim1,dim2); }
                    set { impl.SetAt(dim0, dim1, dim2, value); }
                }
            }
        
            // implementation object
            internal class Matrix3Impl
            {
                private double[] data;
                uint dsize0, dsize1, dsize2; // dimension sizes
                // .. Resize() 
                public double GetAt(uint dim0, uint dim1, uint dim2) {
                    // .. check bounds
                    return data[ (dim2 * dsize1 + dim1) * dsize0 + dim0 ];
                }
                public void SetAt(uint dim0, uint dim1, uint dim2, double value) {
                    // .. check bounds
                    data[ (dim2 * dsize1 + dim1) * dsize0 + dim0 ] = value;
                }
            }
        
            private Matrix3Impl impl;
        
            public Matrix3Elem Elem(uint dim0, uint dim1, uint dim2){
                return new Matrix2Elem(dim0, dim1, dim2);
            }
            // .. Resize
            // .. GetLength0(), GetLength1(), GetLength1()
        }
        

        然后使用这个类型来读写——'foo[1,2,3]'现在写成'foo.Elem(1,2,3).Value',在读值和写时值,位于赋值和值表达式的左侧。

        void normalize(Matrix3 m){
        
            double s = 0;
            for (i = 0; i < input.GetLength0; i++)     
                for (j = 0; j < input.GetLength(1); j++)       
                    for (k = 0; k < input.GetLength(2); k++)
            {
                s += m.Elem(i,j,k).Value;
            }
            for (i = 0; i < input.GetLength0; i++)     
                for (j = 0; j < input.GetLength(1); j++)       
                    for (k = 0; k < input.GetLength(2); k++)
            {
                m.Elem(i,j,k).Value /= s;
            }
        }
        

        同样,增加了开发成本,但共享数据,消除了复制开销和复制相关的开发成本。这是一个权衡。

        【讨论】:

          【解决方案4】:

          作为一种解决方法,您可以创建一个以一维形式维护数组的类(甚至可能更接近裸机形式,以便您可以轻松地将其传递给 COM 库?)然后在此类上重载 operator[] 以使其可用作 C# 代码中的多维数组。

          【讨论】:

            【解决方案5】:

            在不了解您的 COM 库的详细信息的情况下,我会考虑在 .Net 中创建一个外观类,并在必要时将其公开给 COM。
            您的外观将采用 double[,,] 并有一个索引器,该索引器将从 [] 映射到 [,,]。

            编辑:我同意 cmets 中提出的观点,Lorens 的建议更好。

            【讨论】:

            • 这行不通。 COM 将 需要 具有字面量 double[] 数组。如果有的话,您需要创建一个 .NET 类,使 double[] 的行为类似于 double[,,]。
            • 我无法更改 COM 库。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2018-09-23
            • 2020-06-22
            • 2020-10-02
            • 2015-02-07
            • 2015-10-15
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多