1. ホーム
  2. c#

[解決済み] なぜIListやListを使うのか?

2023-05-28 13:08:19

質問

この件に関して多くの投稿があることは知っていますが、なぜIListのようなインターフェースを渡して、具象リストではなくIListのようなインターフェースを返さなければならないのか、まだ混乱しています。

私は、これが後で実装を変更することを容易にするという多くの投稿を読みましたが、私はそれがどのように機能するのか完全に理解していません。

もし私がこのメソッドを持っているとします。

  public class SomeClass
    {
        public bool IsChecked { get; set; }
    }

 public void LogAllChecked(IList<SomeClass> someClasses)
    {
        foreach (var s in someClasses)
        {
            if (s.IsChecked)
            {
                // log 
            }
        }
    }

IListを使うことで、今後どのように役に立つのかがよくわかりません。

すでにメソッドの中にいる場合はどうでしょうか?やはりIListを使うべきでしょうか?

public void LogAllChecked(IList<SomeClass> someClasses)
    {
        //why not List<string> myStrings = new List<string>()
        IList<string> myStrings = new List<string>();

        foreach (var s in someClasses)
        {
            if (s.IsChecked)
            {
                myStrings.Add(s.IsChecked.ToString());
            }
        }
    }

IListを使うことで何が得られるのでしょうか?

public IList<int> onlySomeInts(IList<int> myInts)
    {
        IList<int> store = new List<int>();
        foreach (var i in myInts)
        {
            if (i % 2 == 0)
            {
                store.Add(i);
            }
        }

        return store;
    }

今はどうでしょうか?intのリストについて、何か新しい実装があり、それを変更する必要があるのでしょうか?

基本的に、私は IList を使用することで、単に List をすべてに取り込むよりも何らかの問題を解決できたという、いくつかの実際のコード例を見てみる必要があります。

私の読みでは、私はちょうどものを通してループしているので、私はIListの代わりにIEnumberableを使用することができたと思う。

編集 私はこれを行う方法について、いくつかの私のメソッドで遊んでいました。私はまだ戻り値の型(私がそれをより具体的またはインターフェイスに作るべきかどうか)について確信が持てません。

 public class CardFrmVm
    {
        public IList<TravelFeaturesVm> TravelFeaturesVm { get; set; }
        public IList<WarrantyFeaturesVm> WarrantyFeaturesVm { get; set; }

        public CardFrmVm()
        {
            WarrantyFeaturesVm = new List<WarrantyFeaturesVm>();
            TravelFeaturesVm = new List<TravelFeaturesVm>();
        }
}

 public class WarrantyFeaturesVm : AvailableFeatureVm
    {
    }

 public class TravelFeaturesVm : AvailableFeatureVm
    {
    }

 public class AvailableFeatureVm
    {
        public Guid FeatureId { get; set; }
        public bool HasFeature { get; set; }
        public string Name { get; set; }
    }


        private IList<AvailableFeature> FillAvailableFeatures(IEnumerable<AvailableFeatureVm> avaliableFeaturesVm)
        {
            List<AvailableFeature> availableFeatures = new List<AvailableFeature>();
            foreach (var f in avaliableFeaturesVm)
            {
                if (f.HasFeature)
                {
                                                    // nhibernate call to Load<>()
                    AvailableFeature availableFeature = featureService.LoadAvaliableFeatureById(f.FeatureId);
                    availableFeatures.Add(availableFeature);
                }
            }

            return availableFeatures;
        }

今、私はIListを返しています。これは、このようなプロパティを持っている私のドメインモデルにこれを追加するという単純な事実のためです。

public virtual IList<AvailableFeature> AvailableFeatures { get; set; }

上記は、nhibernateで使うのが標準のようなので、IListそのものを使用しています。そうでなければ、IEnumberableを返したかもしれませんが、よくわかりません。それでも、ユーザーが100%必要とするものは何なのかがわからない(そこがconcreteを返すことの優位性)。

編集 2

また、メソッド内で参照渡しを行いたい場合はどうなるのでしょうか?

private void FillAvailableFeatures(IEnumerable<AvailableFeatureVm> avaliableFeaturesVm, IList<AvailableFeature> toFill)
            {

                foreach (var f in avaliableFeaturesVm)
                {
                    if (f.HasFeature)
                    {
                                                        // nhibernate call to Load<>()
                        AvailableFeature availableFeature = featureService.LoadAvaliableFeatureById(f.FeatureId);
                        toFill.Add(availableFeature);
                    }
                }
            }

は、これで問題が発生するでしょうか?配列(固定サイズ)を渡すことはできないのでしょうか?それは多分具体的なリストのために良いですか?

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

ここでは3つの疑問があります。正式なパラメータにはどのような型を使うべきでしょうか?ローカル変数には何を使うべきか? そして戻り値の型には何を使うべきか?

フォーマルパラメータです。

ここでの原則は 必要以上のものを要求しない . IEnumerable<T> は "このシーケンスの要素を最初から最後まで取得する必要がある" を伝える。 IList<T> は "このシーケンスの要素を任意の順序で取得・設定したい" を伝えます。 List<T> は "私は任意の順序でこのシーケンスの要素を取得および設定する必要があり、私はリストのみを受け付けます; 私は配列を受け付けません。

必要以上のものを要求することで、(1)あなたの不必要な要求を満たすために呼び出し側に不必要な作業をさせる、(2)読み手に虚偽を伝えることになります。 自分が使う分だけを要求しましょう。そうすれば、呼び出し側がシーケンスを持っている場合、あなたの要求を満たすためにその上でToListを呼び出す必要はありません。

ローカル変数。

好きなものを使ってください。それはあなたのメソッドです。メソッドの内部実装の詳細を見ることができるのはあなただけです。

戻り値の型です。

前と同じ原理で、逆になっています。 呼び出し元が必要とする最低限のものを提供する。 呼び出し元がシーケンスを列挙する機能だけを要求している場合、彼らにだけ IEnumerable<T> .