Interfaces to Bridge the Gap
Oftentimes, when working with an API, it is helpful to utilize the best of generics; after all, generics automatically strong-type a class, and avoid boxing/unboxing issues. There can be some downfalls to this approach, however. For instance, if you have an classes called Menu, Document, Window, all of which inherit from the same base class (say UIObject, for instance). The generic strongly-typed collection looks like this:
public class UIObjectCollection<T> : List<T> where T:UIObject { }
However, one of the benefits of polymorphism is that you can work with the base class interface without having to worry about the specifies. For instance, usually Menu, Document, and Window have derived collection classes as such:
public class MenuCollection : UIObjectCollection<Menu> { }
public class DocumentCollection : UIObjectCollection<Document> { }
public class WindowCollection : UIObjectCollection<Window> { }
This approach is very handy, because generics strong-type the collection class, without having to write any additional code. However, sometimes, it helps to work in generalities, and work with the base class of UIObjectCollection. However, with generics, it's not UIObjectCollection, it's UIObjectCollection<Menu> and UIObjectCollection<Document>. This can be problematic.
The solution can be to use an interface. Define an interface as such:
public interface IObjectCollection
{
void Add(UIObject item);
void Remove(UIObject item);
}
Then, in the root collection, define this:
public class UIObjectCollection<T> : List<T>, IObjectCollection where T:UIObject
{
public void Add(T item) { .. }
public void Remove(T item) { .. }
void IObjectCollection Add(UIObject item) { this.Add((T)item); }
void IObjectCollection.Remove(UIObject item) { this.Remove((T)item); }
}
The interface simply reuses the existing methods, simply by casting the parameter. T is a UIObject class anyway, and can be downcast. This situation solves some of the dynamic typing feature that's lacking in .NET. The interface lets you cast MenuCollection and DocumentCollection to IObjectCollection, so you don't have to know the generic type off-hand.