Be careful when creating a collection from another list

In a project on which I’m currently working, I had these classes:

class MultiCriteria : Criteria {
  public MultiCriteria(params Criteria[] criteria) {
    criteriaList = new BindingList<Criteria>(criteria);

  private BindingList<Criteria> criteriaList;
  public BindingList<Criteria> CriteriaList {
    get { return criteriaList; }
    set { criteriaList = value; }

class AllCriteria : MultiCriteria {
  public AllCriteria() { }
  public AllCriteria(params Criteria[] criteria) : base(criteria) { }

If you can already spot the problem, no need to read on. If not, this is what happened: at some later point in the application, I was trying to add criteria to the existing list in an AllCriteria instance, and a NotSupportedException was thrown. Why was that?

As it turns out, the BindingList<T> is derived from Collection<T>, both of these classes have a constructor that takes an IList<T>. So far, no problem – this was what I was trying to use by passing the given criteria down into the BindingList<T> constructor. But I assumed that the given list would be used to initialize the collection, instead the list is used by the Collection<T> implementation as its collection!

So what was happening is this: I was constructing my AllCriteria with its default constructor. Although this doesn’t explicitely call any base class constructor, the base class constructor that takes the params array is apparently sufficient for the compiler not to complain, and this constructor is called on the base class with an array of type Criteria[], but with a length of zero. The Collection<T> finally gets the IList<T> from the array implementation passed in and simply uses this as its own collection. So the result is, obviously, that my freshly constructed binding list is completely empty and readonly – just like the empty Criteria[] array.

The warning is: Be careful what you pass to the constructors of collection types that are derived from Collection<T>! In contrast to the ArrayList and even the List<T>, which have similar constructors but actually copy the information that gets passed in, the data will directly be used by the newly constructed type.

This was tested with VS 2005 beta 2.

Leave a Comment

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s