1. ホーム
  2. c#

[解決済み] IList<T>を返すのは、T[]やList<T>を返すのより悪いのか?

2023-08-09 06:54:32

質問

このような質問に対する回答です。 List<T> またはIList<T> は、コレクションの具体的な実装を返すよりもインターフェイスを返す方が良いということに常に同意しているようです。しかし、私はこれに悩んでいます。インターフェイスのインスタンス化は不可能なので、メソッドがインターフェイスを返していても、実は具体的な実装を返していることになります。これについては、小さなメソッドを2つ書いてちょっと実験してました。

public static IList<int> ExposeArrayIList()
{
    return new[] { 1, 2, 3 };
}

public static IList<int> ExposeListIList()
{
    return new List<int> { 1, 2, 3 };
}

そして、それらを私のテストプログラムで使用します。

static void Main(string[] args)
{
    IList<int> arrayIList = ExposeArrayIList();
    IList<int> listIList = ExposeListIList();

    //Will give a runtime error
    arrayIList.Add(10);
    //Runs perfectly
    listIList.Add(10);
}

どちらの場合も、新しい値を追加しようとすると、コンパイラは何のエラーも出しませんが、明らかに配列を IList<T> として公開するメソッドでは、何かを追加しようとするとランタイムエラーが発生します。 つまり、私のメソッドで何が起こっているのか知らない人が、それに値を追加しなければならない場合、まず最初に私の IListList に追加することで、エラーのリスクを負わずに値を追加することができます。もちろん、タイプチェックを行い、相手が List を扱っているのか、それとも Array を使うことができますが、もしそうせずに、コレクションにアイテムを追加したい場合は をコピーする以外に方法がないのです。 IListList であったとしても List . 配列は決して IList ?

私のもうひとつの懸念は、受け入れ可能な回答である リンクされた質問 (強調) に基づいています。

<ブロッククオート

他の人が使うライブラリを通してクラスを公開する場合。 の場合、一般的には具象実装よりもインターフェースを通して公開したいものです。 これは、後でクラスの実装を変更して別の具象クラスを使用することにした場合に役立ちます。この場合、インターフェイスは変更されないので、ライブラリのユーザはコードを更新する必要がありません。

内部で使うだけであれば、それほど気にすることもなく、Listを使ってもいいかもしれません。

誰かが実際に私の IList<T> から取得した ExposeListIlist() メソッドから取得した値を、そのまま追加/削除しています。すべてうまくいきます。しかし、今、回答が示唆するように、インターフェースを返すことはより柔軟なので、私はリストの代わりに配列を返します(私の側では問題はありません!)、そして、彼らは治療のためにあります...。

TLDRです。

1) インターフェイスを公開すると不要なキャストが発生する?それは問題ないのでしょうか?

2) ライブラリのユーザがキャストを使用しない場合、メソッドを変更すると、メソッドは全く問題なく残っているにもかかわらず、彼らのコードが壊れることがあります。

考えすぎかもしれませんが、インターフェイスを返すことが実装を返すことより好ましいという一般的なコンセンサスは得られません。

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

これはあなたの質問に直接答えるものではないかもしれませんが、.NET 4.5+では、公開または保護されたAPIを設計するときに、私はこれらのルールに従うことを好んでいます。

  • を返します。 IEnumerable<T> もし、列挙しかできない場合は
  • を返す IReadOnlyCollection<T> 列挙と項目数の両方が利用可能である場合。
  • を返す IReadOnlyList<T> もし、列挙、アイテム数、インデックス付きアクセスが可能であれば。
  • を返す ICollection<T> enumeration、items count、modificationが利用可能な場合。
  • を返す IList<T> もし、列挙、アイテム数、インデックス付きアクセス、修正などが可能であれば。

最後の2つのオプションは、メソッドが配列を返してはならないことを前提としています。 IList<T> の実装として配列を返してはいけないと仮定しています。