web-dev-qa-db-ja.com

C#:List <T>とCollection <T>の違い(CA1002、汎用リストを公開しない)

ここでプロジェクトでコード分析を実行しようとしましたが、次のような警告が多数表示されました。

CA1002:Microsoft.Design:Collection、ReadOnlyCollection、またはKeyedCollectionを使用するために、「SomeClass.SomeProtectedOrPublicProperty」の「List <SomeType>」を変更

なぜ_Collection<T>_の代わりに_List<T>_を使用する必要があるのですか? msdnのドキュメントを見ると、ほとんど同じように見えます。警告のエラーヘルプを読んだ後、

System.Collections.Generic.List(T)_は、継承ではなくパフォーマンスのために設計された汎用コレクションであるため、仮想メンバーは含まれていません。

しかし、これは本当に何を意味するのでしょうか?そして、代わりに何をすべきですか?

内部で_List<T>_を使用し続け、代わりにプロパティでnew Collection<T>(someList)を返す必要がありますか?または、_Collection<T>_の代わりに_List<T>_の使用を開始する必要がありますか?

94
Svish

要するに、汎用リストには、拡張ではなく高速になるように設計されているため、追加、削除などの仮想メソッドがありません。これは、この具体的な実装を有用なサブクラスにスワップアウトできないことを意味します(シールされていないため、サブクラス化することはできます)。

したがって、リスト自体を公開することで、クラスのパブリックコントラクトを壊すことなく、コレクションを拡張して(たとえば)追加または削除操作を追跡することはできません。

コレクションをIListまたはそのようなものとして公開することで、実際のバッキングストアとしてリストを使用できますが、クラスのパブリックコントラクトを変更せずに関連する実装を後で交換できるため、将来の拡張性を保持できます。

137
Rob Levine

Collectionは、コレクションが変更されたときにオーバーライドおよび追加機能(通知イベントなど)を提供できる仮想メンバー(挿入、削除、設定、クリア)を公開します。

これは今は必要ないかもしれませんが、コレクションを含むクラスの一般的な要件であるため、事前に計画することをお勧めします。 Collectionは拡張性を考慮して設計されているため、非常に柔軟です。将来、コレクションに追加の機能が必要になった場合、クラスのパブリックインターフェイスを変更せずに拡張することができます。リストを使用していた場合は、リストを使用するために変更する必要があるため、クラスのすべての呼び出し元が壊れていることを意味するコレクションに変更する必要があります。

一方、Listはパフォーマンスを考慮して設計されているため、パフォーマンスが非常に重要な特定の場合にのみ使用してください。それは拡張可能ではないので、リストを使用して何かを将来変更すると、それに依存する他のすべてが壊れます。通常、Listは、非常に低レベルのクラス内でのみ内部的に使用し、将来の重大な変更の可能性を減らすために何にもさらさないでください。

24
Simon P Stevens