views:

611

answers:

6

What are the recommendations for exposing a custom collection vs generic one? e.g

public class ImageCollection : Collection<Image>
{
     ...
}

public class Product
{
   public ImageCollection {get; set;}
}

VS

public class Product
{
   public Collection<Image> Images{get; set;}
}

What cases would you consider creating a custom collection? What are the pros and cons of each method?

+5  A: 

I would go for the second one. The client code has to know the Image type anyway.

The first one only means more code.

Philippe
+1  A: 

The only reason to ever use Collection<T> is if you want to hook into the set of virtual methods which allows you to see all of the mutations to the underlying list. This allows you to do such operations as respond to deletes, implement events, etc ...

If you are not interested responding to or watching these collection modifications then a List<T> is a more appropriate type.

JaredPar
+11  A: 

If you're building a public API, consider using a custom collection for the following advantages.

  • Extensibility - you can add features to your custom collection in the future without changing the API.

  • Backwards compatibility - you are free to change the internals of your collection class as you please, without breaking existing code that clients have programmed against the collection.

  • It's also easier to make potentially breaking changes with less impact. Perhaps later you decide you don't want it to be a Collection<Image>, but a different collection type - you can tailor your ImageCollection class to have the same methods as before, but inherit from something different - and client code will not be likely to break.

If it's just for internal use code, the decision is not necessarily as important, and you may decide to go with "simpler is better".

An example off the top of my head is the ArcGIS Server API's from ESRI - they use custom collections in their APIs. We also use custom collections in our API's mostly for these reasons.

womp
Actually, changing the base type of a class is considered a breaking change, (eg, if client code assigns it to a `Collection<Image>`) but it usually won't matter.
SLaks
I would never, ever recommend referring to any ArcGIS API as an example of a "good" .NET to follow. They use custom collections because they're stuck with wrapping COM - but they also use java-style iterators everywhere in the .NET api, don't expose IEnumerable or IEnumerable<T> where they should, and many other htings that make life very difficult.
Reed Copsey
@Slaks - very true. It mitigates it a lot anyway.
womp
@Reed - notice I didn't say "good" anywhere, haha. It's the first one I thought of because I have to work with WebADF quite a bit.
womp
@womp: I'd never list something, as an example, that is (IMO) as horrific of an API. The fact alone that ESRI used custom collections makes me think that its a poor choice! (Personally, it's not my favorite choice - see my answer as to why, but still, Arc*** APIs are just bad, bad, bad.)
Reed Copsey
I think WebADF got a bad rap due to a few reasons, but I personally didn't find the API design itself that bad. Documentation, performance and bugs were/are all a problem. The javascript/silverlight/flex api's are actually quite good IMO.
womp
+4  A: 

The main reason I can think of is that you might want to have some methods specific to a collection of images that operate on that collection itself. Then I would use an ImageCollection class to contain those methods. Classic encapsulation.

Also, just an aside, you should really only expose a getter for that collection, and initialize a readonly backing field with the actual collection. You probably want people to add/remove items to the collection, not replace the entire thing:

class Product {
    private readonly Collection<Image> _images;
    public Product() { _images = new Collection<Image>(); }
    public Collection<Image> Images { get { return _images; } }
}

-Oisin

x0n
+1 for the tip on the getter.
+3  A: 

In general, it's best to expose one of the interfaces, such as IEnumerable<T>, ICollection<T> or IList<T> instead of a concrete class.

This provides you with much more flexibility in terms of changing your internal API. IEnumerable<T>, in particular, lets you potentially modify your internals later to allow streaming of results, so is the most flexible.

If you know the expected usage patterns of your "collections", you should expose the appropriate API that provides the least constraints on you in the future. If, for example, you know that people just need to iterate your results, expose IEnumerable<T>, so you can change to ANY collection later, or even switch to just using yield return directly.

Reed Copsey
I think i agree with you by using the simplist "collection" for the internal api. But would you expose IEnumerable<T>, ICollection<T> or IList<T> in your public Api? Or would you create a custom "collection" that implements IEnumerable<T>, ICollection<T> or IList<T>, thus covering the pros womp described above?
No. The framework design guidelines book actually (now) suggest exposing IEnumerable<T>, IList<T>, etc, in public APIs. They give you the MOST flexibility to change your internal implementation without breaking the public API. If you implement a custom collection, you're locked to that type forever, unless you want to break API compatibility.
Reed Copsey
+1  A: 

I prefer to have a public generic property to make the internals extensible, but a private field would be the custom one with the actual functionality.

It usually looks like this:

public interface IProduct
{
     ICollection<Image> Images { get; }
}

public class Product : IProduct
{
   private class ImageCollection : Collection<Image>
   {
      // override InsertItem, RemoveItem, etc.
   }

   private readonly ImageCollection _images;
   public ICollection<Image> Images
   {
      get { return _images; }
   }
}

I also often make the custom collection class nested inside a different class, which allows me to modify some private members of the parent class during add/remove.

Groo