PagedDataSource, ICollection and interface design

I've recently been reading
Interface-Oriented Design (Pragmatic Programmers) which has me thinking about the design of interfaces. Yesterday, I ran into an interesting issue using the PagedDataSource with a repeater control. I was binding a custom collection to the repeater through the paged data source and it threw the exception: "Cannot compute Count for a data source that does not implement ICollection." The first thing I have to say about this message is that it was quite useful; it actually identified the exact problem and what I needed to do to fix it. So I added the ICollection interface to my custom collection, and everything started working...

Well, when I implemented ICollection, I actually only implemented the Count property. The interface has three other methods (CopyTo, SyncRoot, and ISynchronized), which I just made throw the NotImplementedException. And my code works fine. So the error message was truly accurate; I only needed to implement the Count property.

This episode illustrates how interface design choices play out. To support the repeater, I only needed a Count property, but because it was expecting an ICollection interface, I had to drag along the rest of the ICollection methods anyway. But I didn't even really implement the methods (they just throw exceptions) because I didn't want to take the time to do it. If, on the other hand, the repeater would have depended on an interface called ICountable that had only a Count property, I would have just added that interface and everything would have worked just as well. But then there would be an ICountable interface in addition to ICollection. I'm sure that most of the time ICollection is a perfectly reasonable set of methods and properties to have on one interface, but in this case it forces me to carry around methods I don't need.

The funny thing was that the collection already had a public property called Count prior to my implementation of the ICollection interface, so if it would have used reflection to find the Count property, rather than accessing it through the interface, it would have worked in the first place.
Definitely makes you see some value in dynamic languages like Ruby where this would have worked fine from the beginning...

0 comments: (+add yours?)