1

として宣言されたクラスがありますpublic class DatumSet : List<datum>

public struct datum {
    public UInt32[] chan;
    public UInt64 sample_number;
    public float time;
    public UInt32 source_sector;
}

リストを反復処理して、いくつかの変更を加えたいと思います。なぜこれが機能しないのですか

        for (int i = 0; i < this.Count; i++) {
            this[i].sample_number = startSample;
            this[i].time = (float)startSample / _sample_rate;
            startSample++;
        }

しかし、これは機能します

        for (int i = 0; i < this.Count; i++) {
            datum d = this[i];
            d.sample_number = sampleNumber;
            d.time = (float)sampleNumber / _sample_rate;
            sampleNumber++;
        }

エラーが発生します:

変数ではないため、'System.Collections.Generic.List.this[int]' の戻り値を変更できません

4

2 に答える 2

13

これは、可変値型を使用した場合に得られるものです:)

インデクサーは、メソッド呼び出しのようなものと考えてください。したがって、この:

this[i].sample_number = startSample;

のようなものです:

GetValue(i).sample_number = startSample;

しかし、は値型 (構造体) であるため、メソッドはリスト内の値のコピーdatumを返します。そのため、それを変更してもまったく役に立ちません。

コンパイラは、あなたがその間違いを犯さないようにしています。

あなたはこれがうまくいくと主張します:

for (int i = 0; i < this.Count; i++) {
    datum d = this[i];
    d.sample_number = sampleNumber;
    d.time = (float)sampleNumber / _sample_rate;
    sampleNumber++;
}

...しかし、実際には何の役にも立ちません。それは以下と同等です:

sampleNumber += this.Count;

それで全部です。コンパイルはしますが、それは動作と同じではありません。

すべての値型を不変にすることをお勧めします。この混乱に陥るのを防ぐのに役立ちます。したがって、値の型として保持し、反復ごとにリストの値を置き換える、クラスに変更して、リストに格納されている参照を介してオブジェクトを変更できます。datum

(いずれにせよ、パブリック フィールドの代わりにプロパティの使用を開始し、.NET 命名規則にも従うことを強くお勧めします。)

于 2012-11-20T22:33:07.580 に答える
9

クラスではなく構造体を使用しているため、問題が発生しています。

コレクションから構造体を取得すると、コピーが作成されます。最初のコード セットは、意図しないことを行っていることを検出するため、エラーを返します。コレクション内のコピーではなく、構造体のコピーを実際に編集することになります。

2 つ目は、編集前にコレクションからコピーを明示的にプルするため、エラーは発生しません。このコードはコンパイルできますが、コレクション内の構造体を変更しないため、期待する結果が得られません。

于 2012-11-20T22:32:37.767 に答える