メンバーコレクションを公開するには、ReadOnlyCollection と IEnumerable のどちらを使うべきでしょうか? 質問する

メンバーコレクションを公開するには、ReadOnlyCollection と IEnumerable のどちらを使うべきでしょうか? 質問する

呼び出しコードがコレクションを反復処理するだけの場合、内部コレクションを 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;
    }
}

おすすめ記事