5

.NET アプリケーションに膨大な数の 3D 配列があります。それらを 1D 配列に変換して、COM ライブラリに渡す必要があります。すべてのデータのコピーを作成せずに配列を変換する方法はありますか?

このような変換を行うことができますが、アプリケーションで問題となるメモリ量を 2 倍使用します。

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

5 に答える 5

8

C# がそのデータをメモリに格納する方法が、C の単純なキャストと同じように実現可能になるとは思えません。最初に 1 次元配列を使用して、その型のクラスを作成して、プログラム内で 3 次元配列であるかのようにアクセスできるようにしてみませんか?

于 2008-09-18T19:33:33.083 に答える
6

残念ながら、C# の配列は、C のような金属に近い言語のように、連続したメモリ内にあることが保証されていません。要素ごとのコピーなしで double[,,] を double[] に変換する方法はありません。

于 2008-09-18T19:32:16.800 に答える
3

プロキシを使用してデータへのアクセスを抽象化することを検討してください(C ++のイテレータ/スマートポインタと同様)。残念ながら、構文はC ++ほどクリーンではなく、operator()はオーバーロードに使用できず、operator []は単一引数ですが、それでも閉じています。

もちろん、この余分なレベルの抽象化により、複雑さと独自の作業が追加されますが、double [,,]オブジェクトを使用する既存のコードに最小限の変更を加えることができ、両方に単一のdouble[]配列を使用できます。相互運用性と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;
    }
}

繰り返しになりますが、開発コストが追加されますが、データを共有するため、コピーのオーバーヘッドと関連する開発コストが削除されます。これはトレードオフです。

于 2008-09-18T20:32:48.560 に答える
1

COM ライブラリの詳細を知らなくても、.Net でファサード クラスを作成し、必要に応じてそれを COM に公開することを検討します。
ファサードは double[,,] を取り、[] から [,,] にマップするインデクサーを持ちます。

編集:コメントで指摘された点については同意します。ローレンスの提案の方が優れています。

于 2008-09-18T19:33:48.200 に答える
1

回避策として、配列を 1 次元形式で保持するクラスを作成し (ベア メタル形式に近いので、COM ライブラリに簡単に渡すことができますか?)、このクラスで operator[] をオーバーロードして、使用できるようにすることができます。 C# コードで多次元配列として。

于 2008-09-18T19:34:47.263 に答える