呼び出しコードがコレクションを反復処理するだけの場合、内部コレクションを IEnumerable ではなく ReadOnlyCollection として公開する理由はありますか?
class Bar
{
private ICollection<Foo> foos;
// Which one is to be preferred?
public IEnumerable<Foo> Foos { ... }
public ReadOnlyCollection<Foo> Foos { ... }
}
// Calling code:
foreach (var f in bar.Foos)
DoSomething(f);
私の見解では、IEnumerable は ReadOnlyCollection のインターフェースのサブセットであり、ユーザーがコレクションを変更することはできません。したがって、IEnumberable インターフェースで十分な場合は、それを使用する必要があります。これは適切な推論方法でしょうか、それとも私が何かを見落としているのでしょうか?
ベストアンサー1
より現代的なソリューション
内部コレクションを変更可能にする必要がない限り、System.Collections.Immutable
パッケージでは、フィールド タイプを不変コレクションに変更し、それを直接公開します (Foo
もちろん、それ自体が不変であると仮定します)。
質問にもっと直接的に答えるために回答を更新しました
呼び出しコードがコレクションを反復処理するだけの場合、内部コレクションを IEnumerable ではなく ReadOnlyCollection として公開する理由はありますか?
それは、呼び出しコードをどれだけ信頼するかによります。このメンバーを呼び出すすべてのものを完全に制御し、保証コードでは決して使用されない:
ICollection<Foo> evil = (ICollection<Foo>) bar.Foos;
evil.Add(...);
コレクションを直接返却すれば、もちろん害はありません。ただし、私は通常、それよりも少し慎重になるようにしています。
同様に、あなたが言うように、もしあなたが必要 IEnumerable<T>
ならば、なぜもっと強いものに自分を縛り付けるのでしょうか?
元の回答
.NET 3.5を使用している場合は、コピーを作成する必要はありません。そして単純なキャストを回避するには、Skip への単純な呼び出しを使用します。
public IEnumerable<Foo> Foos {
get { return foos.Skip(0); }
}
(簡単にラップするためのオプションは他にもたくさんあります。Select Skip
/Where よりも優れている点は、反復ごとに無意味に実行するデリゲートがないことです。)
.NET 3.5 を使用していない場合は、同じことを実行する非常にシンプルなラッパーを記述できます。
public static IEnumerable<T> Wrapper<T>(IEnumerable<T> source)
{
foreach (T element in source)
{
yield return element;
}
}