Prior to generics in .NET, it was common practice to create 'typed' collections so you would have class CarCollection
etc for every type you needed to group. In .NET 2.0 with the introduction of Generics, a new class List<T>
was introduced which saves you having to create CarCollection
etc as you can create List<Car>
.
Most of the time, you will find that List<T>
is sufficient for your purposes, however there may be times that you want to have specific behaviour in your collection, if you believe this to be the case, you have a couple of options:
- Create a class which encapsulates
List<T>
for example public class CarCollection { private List<Car> cars = new List<Car>(); public void Add(Car car) { this.cars.Add(car); }}
- Create a custom collection
public class CarCollection : CollectionBase<Car> {}
If you go for the encapsulation approach, you should at minimum expose the enumerator so you would declare it as follows:
public class CarCollection : IEnumerable<Car>
{
private List<Car> cars = new List<Car>();
public IEnumerator<Car> GetEnumerator() { return this.cars.GetEnumerator(); }
}
Without doing that, you can't do a foreach
over the collection.
Some reasons you might want to create a custom collection are:
- You don't want to fully expose all the methods in
IList<T>
or ICollection<T>
- You want to perform additional actions upon adding or removing an item from the collection
Is it good practice? well that depends on why you are doing it, if it is for example one of the reasons I have listed above then yes.
Microsoft do it quite regularly, here are some fairly recent examples:
As for your FindBy
methods, I would be tempted to put them in extension methods so that they can be used against any collection containing cars:
public static class CarLookupQueries
{
public static Car FindByLicencePlate(this IEnumerable<Car> source, string licencePlate)
{
return source.SingleOrDefault(c => c.LicencePlate == licencePlate);
}
...
}
This separates the concern of querying the collection from the class which stores the cars.
CarCollection
rather than aList<Car>
around? Especially given that CarCollection doesn't extend the backing List class, or even implement the Collection interface (I'm sure that C# has similar things).public class CarCollection
doesn't implement IList or ICollection, etc... thus you can't pass it to something that is ok with a list. It claims as part of its name that it is a collection, but doesn't implement any of those methods.CarColection
with aTotalTradeValue
property on it. DDD isn't the only way to design systems, just pointing it out as an option.