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>! The ArrayList and the List<T> have similar constructors, but actually copy the information that gets passed in. For the Collection<T> however, the data will directly be used by the newly constructed type. This was tested with VS 2005 beta 2.

Sorry, this blog does not support comments.

I used various blog hosting services since this blog was established in 2005, but unfortunately they turned out to be unreliable in the long term and comment threads were lost in unavoidable transitions. At this time I don't want to enable third-party services for comments since it has become obvious in recent years that these providers invariably monetize information about their visitors and users.

Please use the links in the page footer to get in touch with me. I'm available for conversations on Keybase, Matrix, Mastodon or Twitter, as well as via email.