1. ホーム
  2. c#

[解決済み] Collection<T> vs List<T> インターフェースで使うべきものは?

2022-04-23 11:43:28

質問

コードは以下のようになります。

namespace Test
{
    public interface IMyClass
    {
        List<IMyClass> GetList();
    }

    public class MyClass : IMyClass
    {
        public List<IMyClass> GetList()
        {
            return new List<IMyClass>();
        }
    }
}

コード解析を実行すると、以下のような勧告が表示されます。

警告 3 CA1002 : マイクロソフト.デザイン: IMyClass.GetList()' の 'List' を Collection、ReadOnlyCollection または KeyedCollection を使用するように変更する。

どのように修正すればよいのでしょうか。また、ここでいうグッドプラクティスとは何でしょうか。

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

なぜダメなのか、という"why"の部分に答えるために List<T> 理由は、将来性、APIの簡素化です。

将来性

List<T> は、サブクラス化することで簡単に拡張できるように設計されているわけではなく、内部実装のために高速に設計されています。このメソッドは virtual ではないのでオーバーライドできません。 Add Insert / Remove の操作を行うことができます。

つまり、将来的にコレクションの動作を変更する必要がある場合(例えば、人々が追加しようとするNULLオブジェクトを拒否したり、クラスの状態を更新するなど、NULLが発生したときに追加の作業を行うなど)、返すコレクションのタイプをサブクラス化できるものに変更する必要があり、これは破格のインターフェース変更となります(もちろん、NULLを許可しないなどの意味論の変更もインターフェース変更となるかもしれませんが、内部のクラス状態の更新などは、そうではないでしょう)。

というように、簡単にサブクラス化できるクラスを返すことで、そのようなクラスは不要になります。 Collection<T> のようなインターフェースか IList<T> , ICollection<T> または IEnumerable<T> を使用すると、内部実装を変更して別のコレクション・タイプにすることができ、消費者が期待するタイプとして返すことができるので、消費者のコードを壊すことはありません。

APIの簡素化

List<T> のような便利な操作がたくさん含まれています。 BinarySearch , Sort といった具合です。しかし、もしこれがコレクションを公開しているのであれば、リストのセマンティクスは消費者ではなく、あなたがコントロールすることになるでしょう。ですから、あなたのクラスが内部的にこれらの操作を必要とすることはあっても、あなたのクラスの消費者がそれらを呼び出したいと思うことはほとんどないでしょう(あるいは、呼び出すべきです)。

このように、よりシンプルなコレクションクラスやインターフェースを提供することで、APIの利用者が目にするメンバーの数を減らし、利用しやすくすることができます。