171

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

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

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

コード分​​析を実行すると、次の推奨事項が表示されます。

警告 3 CA1002 : Microsoft.Design : Collection、ReadOnlyCollection、または KeyedCollection を使用するように 'IMyClass.GetList()' の 'List' を変更してください

これをどのように修正する必要がありますか?ここでの良い習慣は何ですか?

4

8 に答える 8

249

なぜそうしないのかという質問の「なぜ」の部分に答えるためにList<T>、その理由は将来を保証し、APIをシンプルにすることです。

将来を見据えた

List<T>サブクラス化することで簡単に拡張できるようには設計されていません。内部実装が高速になるように設計されています。そのメソッドは仮想ではないため、オーバーライドできず、Add//操作へのフックがないことに気付くでしょう。InsertRemove

つまり、将来コレクションの動作を変更する必要がある場合(たとえば、ユーザーが追加しようとするnullオブジェクトを拒否したり、クラスの状態の更新など、これが発生したときに追加の作業を実行したりする場合)、タイプを変更する必要があります。コレクションの1つに戻ると、サブクラス化できます。これは、重大なインターフェイスの変更になります(もちろん、nullを許可しないなどのセマンティクスの変更もインターフェイスの変更になる可能性がありますが、内部クラスの状態の更新などはそうではありません)。

したがって、などのように簡単にサブクラス化できるクラス、またはなどCollection<T>のインターフェイスを返すか、内部実装をニーズに合わせて別のコレクションタイプに変更することで、コンシューマーのコードを壊すことなく、次のように返すことができます。彼らが期待しているタイプ。IList<T>ICollection<T>IEnumerable<T>

APIのシンプルさ

List<T>BinarySearchなどの便利な操作がたくさん含まれていSortます。ただし、これが公開しているコレクションである場合は、コンシューマーではなく、リストのセマンティクスを制御している可能性があります。したがって、クラスが内部でこれらの操作を必要とする場合でも、クラスのコンシューマーがそれらを呼び出したい(または呼び出す必要がある)可能性はほとんどありません。

そのため、よりシンプルなコレクションクラスまたはインターフェースを提供することで、APIのユーザーに表示されるメンバーの数を減らし、ユーザーが使いやすくします。

于 2008-11-07T11:45:24.417 に答える
51

具体的なコレクションではなく、インターフェイスを返すように個人的に宣言します。本当にリストへのアクセスが必要な場合は、 を使用してIList<T>ください。それ以外の場合は、 と を検討ICollection<T>してIEnumerable<T>ください。

于 2008-11-07T10:29:33.023 に答える
6

「なぜ」の部分はまだ誰も答えていないと思います...だからここに行きます。Collection<T>a の代わりに aを「使用する必要がある」理由は、 aList<T>を公開するList<T>と、オブジェクトにアクセスできる人なら誰でもリスト内の項目を変更できるためです。独自Collection<T>の「追加」、「削除」などのメソッドを作成していることを示すはずです。

おそらく、自分自身 (または数人の同僚) のためだけにインターフェースをコーディングしているので、おそらく心配する必要はありません。意味のある別の例を次に示します。

パブリック配列がある場合、例:

public int[] MyIntegers { get; }

「get」アクセサーしかないため、誰も値をいじることができないと思うかもしれませんが、そうではありません。誰でも次のように内部の値を変更できます。

someObject.MyIngegers[3] = 12345;

個人的にはList<T>、ほとんどの場合に使用します。しかし、ランダムな開発者に配布するクラス ライブラリを設計していて、オブジェクトの状態に依存する必要がある場合は、独自のコレクションを作成し、そこからロックする必要があります。 )

于 2008-11-07T10:41:45.137 に答える
2

List オブジェクトを公開して直接操作するのではなく、独自の実装を抽象化することが主な目的です。

他のオブジェクト (または人) がオブジェクトの状態を直接変更できるようにすることはお勧めできません。プロパティのゲッター/セッターを考えてみてください。

Collection -> 通常のコレクションの場合
ReadOnlyCollection -> 変更してはいけないコレクションの
場合 KeyedCollection -> 代わりに辞書が必要な場合。

それを修正する方法は、クラスに何をさせたいか、および GetList() メソッドの目的によって異なります。詳しく教えていただけますか?

于 2008-11-07T11:09:56.813 に答える
1

これが尋ねられてから長い時間が経ちましたが、追加するものがあります。

List<T>リスト型がではなくから派生する場合、Collection<T>実装する保護された仮想メソッドを実装できませんCollection<T>。これが意味することは、リストに変更が加えられた場合、派生型は応答できないということです。これは、List<T>アイテムを追加または削除するときに認識していると想定しているためです。通知に応答できることはオーバーヘッドであるため、List<T>提供しません。

外部コードがコレクションにアクセスする場合、アイテムがいつ追加または削除されるかを制御できない場合があります。したがってCollection<T>、リストがいつ変更されたかを知る方法を提供します。

于 2015-11-11T16:08:39.157 に答える
1

このような場合、私は通常、必要最小限の実装を公開しようとします。実際にリストを使用していることを消費者が知る必要がない場合は、リストを返す必要はありません。Microsoft がコレクションを提案するように返すことで、クラスのコンシューマーからリストを使用しているという事実を隠し、内部の変更からそれらを分離します。

于 2008-11-07T11:11:25.343 に答える
0

次のようなものを返すことに問題はありません

this.InternalData.Filter(crteria).ToList();

内部データの切り離さ れたコピー、またはデータ クエリの切り離された結果を返したList<TItem>場合、実装の詳細を公開することなく安全に返すことができ、返されたデータを便利な方法で使用できます。

しかし、これは私が期待する消費者のタイプに依存します-これがデータグリッドのようなものである場合、ほとんどの場合IEnumerable<TItem> 、アイテムのコピーされたリストになるものを返すことを好みます:)

于 2012-01-14T03:14:01.460 に答える
-1

Collection クラスは、実装の詳細やその他の機能を隠すための、他のコレクションの単なるラッパー クラスです。これは、オブジェクト指向言語のプロパティ隠蔽コーディング パターンと関係があると思います。

気にする必要はないと思いますが、本当にコード分析ツールを喜ばせたい場合は、次のようにしてください。

//using System.Collections.ObjectModel;

Collection<MyClass> myCollection = new Collection<MyClass>(myList);
于 2008-11-07T10:35:16.773 に答える