I have created a class, MonitoredCollection<T>, that basically encapsulates/mimics List but allows me to fire events on certain calls.
Now however, whereever there is a parameter that takes a MonitoredCollection, where T is an Interface, I can no longer pass a MonitoredCollection<T> where T is a class that implements that interface, like I could with a List.
I always thought that interfaces were a language ‘feature’ and therefore I don’t need to implement anything more to support this, so what have I missed?
EDIT: Sorry, I made a mistake in that question, as João correctly pointed out List never worked in this instance so the question is as it stands without that!
Suppose you have a
MonitoredCollection<SomeObject>instance, and you want to treat it as aMonitoredCollection<ISomeInterface>instance whereSomeObjectdoes in fact implementISomeInterface. This does not create any problems for retrieving items from the collection, since object of typeSomeObjectcan be converted to the interface typeISomeInterface.However, for all the methods on your collection which modify the collection, such as those that assign a new value to an index, or insert a new item into the collection, this cast has created a whole suite of issues. I’d assume your
MonitoredCollection<SomeObject>instance would have a method such asAdd(SomeObject obj), which would insert a new object into the collection. After the cast, the signature on this method would beAdd(ISomeInterface obj). This seems to make sense, but not allISomeInterfaceobjects are NECESSARILYSomeObjectinstances.Because the casted object will allow operations on the collection that the original object wouldn’t allow, the runtime won’t allow this cast. C# 4.0 introduced covariance and contravariance to explicitly state what is valid for casts of this type, you can look into them for trying to solve this issue. However, you’re really only going to have luck with a read only version of your collection (think
List<T>.AsReadOnly()).