Возможно ли преобразовать массив C # double [] в double [] без создания копии

У меня есть огромные 3D-массивы чисел в моем приложении .NET. Мне нужно преобразовать их в массив 1D, чтобы передать его в библиотеку 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;
0
добавлено
Просмотры: 21

5 ответы

К сожалению, массивы C# не гарантированно находятся в непрерывной памяти, например, они находятся в более близких к металлическим языками, таких как C. Таким образом, нет. Невозможно преобразовать double [] в double [] без поэтапной копии.

0
добавлено

Не зная подробностей вашей библиотеки COM, я бы посмотрел на создание класса фаз в .Net и, если нужно, подвергая его COM.
Ваш фасад примет двойной [] и будет иметь индекс, который будет отображаться с [] на [].

Редактировать: Я согласен с точками, сделанными в комментариях, предложение Лоренса лучше.

0
добавлено
Я не могу изменить библиотеку COM.
добавлено автор Hallgrim, источник
Это не сработает. COM будет нужен , чтобы иметь литерал double []. Во всяком случае, вы хотите создать класс .NET, который сделал double [] как double [].
добавлено автор Jonathan Rupp, источник

В качестве обходного пути вы можете создать класс, который поддерживает массив в одномерной форме (возможно, даже ближе к голой металлической форме, чтобы вы могли легко передать его в библиотеку COM?), А затем перегрузить оператор [] в этом классе, чтобы сделать его пригодным для использования как многомерный массив в вашем коде C #.

0
добавлено

Я не верю, что C# хранит, что данные в памяти сделают это возможным так же, как и простой актер в C. Почему бы не использовать 1d-массив для начала и, возможно, создать класс для типа, чтобы вы могли получить к нему доступ в своей программе, как если бы это был 3D-массив?

0
добавлено

Рассмотрим абстрагирование доступа к данным с помощью прокси (аналогично итераторам/смарт-указателям на C ++) , К сожалению, синтаксис не так чист, как C ++, поскольку оператор() недоступен для перегрузки, а оператор [] является единственным аргументом, но все еще закрыт.

Конечно, этот дополнительный уровень абстракции добавляет сложности и собственной работы, но это позволит вам внести минимальные изменения в существующий код, который использует объекты double [], позволяя вам использовать единственный двойной массив [] для обоих interop и ваш 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;
    }
}

Опять же, добавлены затраты на разработку, но делятся данными, устраняя накладные расходы на копирование и копируя связанные с этим затраты на разработку. Это компромисс.

0
добавлено