Es ist möglich, C # double [] Array in double [] umzuwandeln, ohne eine Kopie zu erstellen

Ich habe riesige 3D-Arrays von Zahlen in meiner .NET-Anwendung. Ich muss sie in ein 1D-Array konvertieren, um es an eine COM-Bibliothek zu übergeben. Gibt es eine Möglichkeit, das Array zu konvertieren, ohne eine Kopie aller Daten zu erstellen?

Ich kann die Konvertierung so machen, aber dann verwende ich doppelt so viel Speicher, was ein Problem in meiner Anwendung ist:

  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

5 Antworten

Leider sind C# -Arrays nicht im zusammenhängenden Speicher garantiert, so wie sie in näher bei den Metallsprachen wie C sind. Also, nein. Es gibt keine Möglichkeit, double [] in double [] ohne eine elementweise Kopie zu konvertieren.

0
hinzugefügt

Ohne die Details Ihrer COM-Bibliothek zu kennen, würde ich eine Fassadenklasse in .Net erstellen und sie bei Bedarf COM aussetzen.
Deine Fassade würde einen doppelten [] nehmen und einen Indexer haben, der von [] nach [] abbildet.

Edit: Ich stimme den in den Kommentaren gemachten Aussagen zu, Lorens Vorschlag ist besser.

0
hinzugefügt
Ich bin nicht in der Lage, die COM-Bibliothek zu ändern.
hinzugefügt der Autor Hallgrim, Quelle
Dies wird nicht funktionieren. COM benötigt , um das Literal double [] -Array zu haben. Wenn überhaupt, möchten Sie eine .NET-Klasse erstellen, die double [] wie ein Double [] behandelt.
hinzugefügt der Autor Jonathan Rupp, Quelle

Als Workaround könnten Sie eine Klasse erstellen, die das Array in eindimensionaler Form (vielleicht sogar näher an der Bare-Metal-Form, so dass Sie es einfach an die COM-Bibliothek übergeben können) und dann den Operator [] für diese Klasse überladen, um es nutzbar zu machen als mehrdimensionales Array in Ihrem C# -Code.

0
hinzugefügt

Ich glaube nicht, dass die Art, wie C# diese Daten im Speicher speichert, es genauso möglich machen würde wie eine einfache Umwandlung in C. Warum nicht ein 1d-Array verwenden und vielleicht eine Klasse für den Typ erstellen, damit Sie in Ihrem Programm darauf zugreifen können, als wäre es ein 3D-Array?

0
hinzugefügt

Berücksichtigen Sie den Abstrahierungszugriff auf die Daten mit einem Proxy (ähnlich wie Iteratoren/Smartpointer in C ++). . Leider ist die Syntax nicht so sauber wie C ++, da operator() nicht für Überladung verfügbar ist und operator [] einfach-arg ist, aber immer noch geschlossen.

Natürlich bringt dieses zusätzliche Abstraktionsniveau zusätzliche Komplexität und Arbeit mit sich, aber es würde Ihnen erlauben, minimale Änderungen an existierendem Code zu machen, der doppelte [] Objekte verwendet, während Sie für beide ein einziges double [] -Array verwenden können Interop und Ihre In-C # Berechnung.

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()
}

Und dann diesen Typ zum Lesen und Schreiben verwenden - 'foo [1,2,3]' wird jetzt als 'foo.Elem (1,2,3) .Value', in beiden Lesewerte und Schreibwerte, auf linke Seite von Zuweisungs- und Wertausdrücken.

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;
    }
}

Erneut, zusätzliche Entwicklungskosten, aber teilt Daten, Entfernen von Kopieraufwand und Kopieren der damit verbundenen Entwicklungskosten. Es ist ein Kompromiss.

0
hinzugefügt