1. ホーム
  2. c#

[解決済み] メンバーコレクションを公開するにはReadOnlyCollectionかIEnumerableか?

2022-07-05 20:56:45

質問

呼び出し側のコードがコレクションを反復処理するだけなら、内部コレクションを 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 のインターフェースのサブセットで、ユーザがコレクションを変更することはできません。ですから、もし IEnumerable インターフェースで十分であれば、それを使用することになります。それはそれについて推論する適切な方法ですか、それとも私は何かを見逃していますか?

ありがとうございます/Erik

どのように解決するのですか?

より現代的な解決策

内部コレクションをミュータブルにする必要がなければ 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); }
}

(トリビアルにラップするための他のオプションはたくさんあります。 Skip の良いところは、反復のたびに無意味に実行するデリゲートがないことです)。

.NET 3.5を使用していない場合は、同じことを行うための非常に簡単なラッパーを書くことができます。

public static IEnumerable<T> Wrapper<T>(IEnumerable<T> source)
{
    foreach (T element in source)
    {
        yield return element;
    }
}