Writing another question for SO, I came to a pattern that I use very often and I never really reflected about. But now, I’m no longer sure if this is the right way:
If I have collections that my WPF-controls will bind to, I returned almost always IEnumerable<SomeType>. However internally , this is in most cases an ReadOnlyObservableCollection<SomeType>. I never had a problem with this and all consuming controls always updated correctly, what is not astonishing because they check for the INotifyCollectionChanged-interface.
But my question is now, if this is bad practice to declare in the signature only the IEnumerable<SomeType> but to return (and also depend on) something much more powerful (INotifyCollectionChanged).
Update:
I try to clarify:
My main intention is to return an IEnumerable<SomeType>. But most of the time, the returned IEnumerable<SomeType> implements also INotifyCollectionChanged such as ReadOnlyObservableCollection<SomeType> does. The consuming controls bind accordingly (what my second intention is).
Maybe I should have asked: Is there an interface that exactly contains IEnumerable and INotifyPropertyChanged.
Remember,
IEnumerable<T>andINotifyCollectionChangedare both interfaces – they aren’t a definitive type. You can design your concrete class to implement both, with no problems. Your API can return the appropriate interface for the method call. This is, in fact, a good design – not something to avoid.ObservableCollection<T>does this (indirectly viaCollection<T>), and also implementsIList<T>as well as other interfaces.If you are making your own custom collection, and plan to use it with data binding, I would make it implement
IEnumerable<T>(or potentiallyIList<T>, if appropriate) andINotifyCollectionChanged. This will give it the best usability, both from code, but also for efficient binding.However, depending on an interface to exist that isn’t part of the API is bad practice. This is dangerous, and part of the reason to return an interface instead of a concrete type is to allow the implementation to change later. By putting a dependency on an interface that isn’t declared, you’re making your code fragile.
That being said, I often do what you’re attempting, but it’s not a “hard” dependency. Rather, I use
IEnumerable<T>, and check forINotifyCollectionChanged– taking advantage of it if it is implemented. I do, however, allow the code to work if the “secondary” interface doesn’t exist.