3

プライベートコレクションを呼び出し元に返すメソッドがあり、呼び出し元が返されたコレクションを変更できないようにしたい。

private readonly Foo[] foos;

public IEnumerable<Foo> GetFoos()
{
    return this.foos;
}

現時点ではプライベートコレクションは固定配列ですが、実行時に新しいアイテムを追加する必要が生じた場合、将来的にコレクションがリストになる可能性があります。

呼び出し元がコレクションを変更できないようにするための解決策がいくつかあります。戻りIEnumerable<T>値は最も簡単な解決策ですが、呼び出し元は戻り値をコレクションにアップキャストしてIList<T>変更することができます。

((IList<Foo>)GetFoos())[0] = otherFoo;

コレクションのクローンを作成することには、独立して進化できる2つのコレクションがあるという明らかな欠点があります。これまで、次のオプションを検討してきました。

  1. コレクションをでラップしReadOnlyCollection<T>ます。
  2. Enumerableのようなダミーの射影を実行することにより、クラスによって定義されたLINQイテレータの1つを返しますlist.Select(item => item)Where(item => true)返されたイテレータの方が軽量に見えるので、実際に使用することを検討します。
  3. カスタムラッパーを作成します。

私が使用するのが好きではないのReadOnlyCollection<T>は、それが実装されており、インデクサーをIList<T>呼び出しAdd()たりアクセスしたりすると例外が発生することです。これは理論的には絶対に正しいですが、実際のコードチェックIList<T>.IsReadOnlyIList<T>.IsFixedSize

LINQイテレータを使用すると(コードを拡張メソッドでラップしましたMakeReadOnly())、このシナリオを防ぐことができますが、ハックのような味がします。

カスタムラッパーを作成しますか?車輪の再発明?

考え、考慮事項、またはその他の解決策はありますか?


この質問にタグを付けているときに、以前は気づかなかったこのStackOverflowの質問を発見しました。Jon Skeetも「LINQハック」を使用することを提案していますが、を使用するとさらに効率的Skip(0)です。

4

4 に答える 4

5

残念ながら、現在のバージョンのフレームワークで探しているものを正確に実現する方法はありません。具象型とインターフェース・スタイルの両方で、索引付け可能な不変/読み取り専用コレクションの概念がないだけです。

ご指摘のとおりReadOnlyCollection<T>、コンクリートタイプ側でも問題なく動作します。ただし、静的に読み取り専用である、実装する対応するインターフェイスはありません。

あなただけが本当の選択は...

  • 独自のコレクションクラスを定義する
  • IEnumerable<T>コレクションが実装する必要な読み取り専用インターフェースのみを実装または定義します。
于 2009-08-02T17:04:02.610 に答える
0

返されるオブジェクトのディープ コピーを作成するのはどうですか? [そのため、呼び出し元が返されたコピーを変更することを決定した場合でも、元のコレクションには影響しません]

于 2009-08-02T18:03:08.243 に答える
0

そのような場合、クラス内にメソッドを作成して、プライベート コレクションの個々の要素にアクセスします。プライベート コレクションを含むクラスでインデクサー ( http://msdn.microsoft.com/en-us/library/6x16t2tx.aspx ) を実現することもできます。

于 2009-08-02T20:00:03.030 に答える
0

List と Array には AsReadOnly メソッドがあります。

public IEnumerable<Foo> GetFoos()
{
    return Array.AsReadOnly(this.foos);
    // or if it is a List<T>
    // return this.foos.AsReadOnly();
}
于 2009-08-02T18:10:48.690 に答える