別のクラスのClassCollectionを作成することをお勧めしますか?


35

Carクラスがあると言いましょう:

public class Car
{
    public string Engine { get; set; }
    public string Seat { get; set; }
    public string Tires { get; set; }
}

駐車場に関するシステムを作成しているとしましょう。私は多くのCarクラスを使用するので、クラスを作成しCarCollectionますFindCarByModel

public class CarCollection
{
    public List<Car> Cars { get; set; }

    public Car FindCarByModel(string model)
    {
        // code here
        return new Car();
    }
}

クラスを作成している場合ParkingLot、ベストプラクティスは何ですか?

オプション1:

public class ParkingLot
{
    public List<Car> Cars { get; set; }
    //some other properties
}

オプション#2:

public class ParkingLot
{
    public CarCollection Cars { get; set; }
    //some other properties
}

ClassCollection別のものを作成することは良い習慣Classですか?


あなたCarCollectionList<Car>周りではなくを渡すことでどのような利益を感じますか?特に、CarCollectionはバッキングリストクラスを拡張せず、Collectionインターフェイスさえ実装していないことを考えると(C#には同様のものがあると確信しています)。

リスト<T>すでに実装のIList <T>、ICollectionを<T>、IListを、ICollectionを、IReadOnlyList <T>、IReadOnlyCollection <T>、IEnumerableを<T>とIEnumerableを...また、私はLINQのを使用することができます...
ルイス

しかしpublic class CarCollection、IListやICollectionなどは実装していません。したがって、リストで問題のないものに渡すことはできません。名前の一部として、それがコレクションであると主張していますが、これらのメソッドは実装していません。

1
6年前の質問なので、これがDDDの一般的な慣行であるとは誰も言及していません。すべてのコレクションは、カスタムコレクションに抽象化する必要があります。たとえば、自動車のグループの価値を計算したいとします。そのロジックをどこに置きますか?サービスで?または、DDD CarColectionでは、TotalTradeValueプロパティがあります。DDDはシステムを設計する唯一の方法ではなく、オプションとして指摘するだけです。
ストームミュラー

1
まさに、これらはDDDで提案されているように、実際には集約されたルートです。むしろ駐車場、またはワークエリアなどのようないくつかの名前を使う
コードネームジャック

回答:


40

.NETのジェネリックの前は、「型付き」コレクションを作成class CarCollectionして、グループ化する必要のあるすべての型に対してなどを使用することが一般的でした。.NET 2.0では、Generics List<T>が導入され、新しいクラスが導入されました。これにより、作成できるCarCollectionなどの作成を省くことができますList<Car>

ほとんどの場合、それList<T>は目的には十分ですが、コレクション内で特定の動作を行いたい場合があります。そうだと思われる場合は、いくつかのオプションがあります。

  • List<T>たとえば、カプセル化するクラスを作成しますpublic class CarCollection { private List<Car> cars = new List<Car>(); public void Add(Car car) { this.cars.Add(car); }}
  • カスタムコレクションを作成する public class CarCollection : CollectionBase<Car> {}

カプセル化アプローチを採用する場合は、少なくとも列挙子を公開して、次のように宣言する必要があります。

public class CarCollection : IEnumerable<Car>
{
    private List<Car> cars = new List<Car>();

    public IEnumerator<Car> GetEnumerator() { return this.cars.GetEnumerator(); }
}

そうしないとforeach、コレクションをやり直すことはできません。

カスタムコレクションを作成する理由は次のとおりです。

  • IList<T>またはですべてのメソッドを完全に公開したくないICollection<T>
  • コレクションにアイテムを追加または削除するときに追加のアクションを実行したい

それは良い習慣ですか?それはあなたがそれをしている理由に依存します。例えば、それが上に挙げた理由の1つであれば、そうです。

Microsoftは非常に定期的にそれを行っていますが、ここにかなり最近の例をいくつか示します。

あなたのFindByメソッドについては、車を含むコレクションに対して使用できるように拡張メソッドに入れたいと思います:

public static class CarLookupQueries
{
    public static Car FindByLicencePlate(this IEnumerable<Car> source, string licencePlate)
    {
        return source.SingleOrDefault(c => c.LicencePlate == licencePlate);
    }

    ...
}

これにより、コレクションを照会する懸念と、車を格納するクラスを区別します。


このアプローチに従って、すべてのメソッドをカプセル化ClassCollectionする新しいCarCRUDものを追加することで、追加、削除、更新メソッドの偶数を却下することもできます
ルイス

@Luis CarCRUD拡張機能の使用を強制するのは難しいため、この拡張機能はお勧めしません。カスタムクラスロジックをコレクションクラスに配置する利点は、拡張機能をバイパスする方法がないことです。さらに、Caretcが宣言されているコアアセンブリ内の検索ロジックは実際には気にしないかもしれません。これはUIのみのアクティビティかもしれません。
トレバーピリー

MSDNからのメモとして、「新しい開発にCollectionBaseクラスを使用することはお勧めしません。代わりに、汎用のCollection <T>クラスを使用することをお勧めします。」- docs.microsoft.com/en-us/dotnet/api/...
ライアン

9

いいえ。XXXCollectionクラスの作成は、.NET 2.0でのジェネリックの出現により、ほとんどスタイルから外れました。実際、Cast<T>()これらのカスタム形式からデータを取得するために最近使用されている気の利いたLINQ拡張機能があります。


1
その中に含めることができるカスタムメソッドはClassCollectionどうですか?それらをメインに置くのは良い習慣Classですか?
ルイス

3
それは「依存する」というソフトウェア開発のマントラに該当すると信じています。たとえば、FindCarByModelメソッドについて話している場合、それはリポジトリ上のメソッドとして理にかなっています。これは単なるCarコレクションよりも少し複雑です。
ジェシーC.スライサー

2

上記のFindByCarModelの例のように、ドメイン指向のメソッドを使用してコレクションを検索/スライスすると便利ですが、ラッパーコレクションクラスを作成する必要はありません。この状況では、通常、拡張メソッドのセットを作成します。

public static class CarExtensions
{
    public static IEnumerable<Car> ByModel(this IEnumerable<Car> cars, string model)
    {
        return cars.Where(car => car.Model == model);
    }
}

必要な数のフィルターまたはユーティリティメソッドをそのクラスに追加し、どこでも使用できますIEnumerable<Car>。これには、何でも、などのICollection<Car>配列が含まれます。CarIList<Car>

永続化ソリューションにはLINQプロバイダーがあるため、頻繁に操作してreturnを実行する同様のフィルターメソッドも作成するIQueryable<T>ため、これらの操作をリポジトリにも適用できます。

.NETのイディオム(まあ、C#)は1.1から大きく変わりました。カスタムコレクションクラスの維持は苦痛であり、CollectionBase<T>ドメイン固有のフィルターおよびセレクターメソッドのみが必要な場合、拡張メソッドソリューションでは得られないものから継承することはほとんど得られません。


1

他の項目のコレクションを保持するための特別なクラスを作成する唯一の理由は、価値のあるものを追加するときであると思います。それは単に、インスタンスIListまたは別のタイプのコレクションからカプセル化/継承する以上のものです。

たとえば、あなたの場合、偶数/不均等なロットスペースに駐車された車のサブリストを返す関数を追加します...そしてそれでも...多分それが頻繁に再利用される場合のみです。関数であり、一度だけ使用されますが、ポイントは何ですか?キス

さて、あなたが多くのソート/検索メソッドを提供することを計画しているなら、はい、これはその特別なコレクションクラスでそれらが属するべき場所だからです。これは、いくつかの「検索」クエリの複雑さや、ソート/検索方法でできることを「隠す」ための良い方法でもあります。


さえカントー、私は私がメインで、これらの方法にはできると思いますClass
ルイス・

はい、確かに...できること
Jalayn

-1

次のオプションを使用することをお勧めします。そのため、コレクションにメソッドを追加し、リストの利点を活用できます。

public class CarCollection:List<Car>
{
    public Car FindCarByModel(string model)
    {
        // code here
        return new Car();
    }
}

そして、あなたはC#7.0のようにそれを使用することができます

public class ParkingLot
{
    public CarCollection Cars { get; set; }=new CarCollection();
    //some other properties
}

または、次のように使用できます

public class ParkingLot
{
   public ParkingLot()
   {
      //initial set
      Cars =new CarCollection();
   }
    public CarCollection Cars { get; set; }
    //some other properties
}

-@Bryanコメントのおかげで一般的なバージョン

   public class MyCollection<T>:List<T> where T:class,new()
    {
        public T FindOrNew(Predicate<T> predicate)
        {
            // code here
            return Find(predicate)?? new T();
        }
       //Other Common methods
     }

そして、あなたはそれを使用することができます

public class ParkingLot
{
    public MyCollection<Car> Cars { get; set; }=new MyCollection<Car>();
    public MyCollection<Motor> Motors{ get; set; }=new MyCollection<Motor>();
    public MyCollection<Bike> Bikes{ get; set; }=new MyCollection<Bike>();
    //some other properties
}

List <T>から継承しないでください
ブライアンベッチャー

@ブライアン、あなたは正しい質問はジェネリックコレクションのためではありません。ジェネリックコレクションの回答を変更します。
ワリードAK

1
: -あなたはまだそれをしなかった@WaleedAKはリスト<T>から継承されません stackoverflow.com/questions/21692193/why-not-inherit-from-listt
ブライアン・ベッチャー

@Bryan:リンクを読んだ場合、いつ受け入れられますか?List <T>メカニズムを拡張するメカニズムを構築している場合。、だから、限り、追加のプロパティが存在しないと罰金になります
ワリードAKを
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.