Friday, 23 August 2013

Odd use of Explicit Interface Implementation

I was trying to write a myConcurrentDictionary.Remove line today, but Visual Studio would prevent me from doing so saying that ConcurrentDictionary<K,V> lacks that method. Well, ConcurrentDictionary implements IDictionary, so it has to feature a Remove method! Looking into MSDN we can see that Remove comes as an Explicit Interface Implementation, so in order to use it you'll need a cast (IDictionary)myConcurrentDictionary.Remove(...);

OK, my understanding of Explicit Interface Implementations is that you use them when your class implements several interfaces with colliding methods and you want to give a different implementation of such method for each interface. ConcurrentDictionary implements 4 different interfaces (IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IDictionary, ICollection) that sport a Remove method. The signatures are a slightly different and somehow colliding (TKey, Object...) so this Explicit implementation makes things clear, but, why don't they add a non Explicit Remove(TKey) method?, that would be the most commonly used. It seems as if they were preventing the use of Remove by sort of hiding it.

Well, some searching confirms that impression. Here we can read:

Explicit interface implementations can be used to disambiguate class and interface methods that would otherwise conflict. Explicit interfaces can also be used to hide the details of an interface that the class developer considers private.

And then we find this and this excellent discussions in StackOverflow, with answers from Jon Skeet:

It allows you to implement part of an interface in a "discouraging" way - for example, ReadOnlyCollection implements IList, but "discourages" the mutating calls using explicit interface implementation. This will discourage callers who know about an object by its concrete type from calling inappropriate methods. This smells somewhat of interfaces being too broad, or inappropriately implemented - why would you implement an interface if you couldn't fulfil all its contracts? - but in a pragmatic sense, it can be useful.

and Eric Lippert:

"Discouragement" also allows you to effectively "rename" the interface methods. For example, you might have class C : IDisposable { void IDisposable.Dispose() { this.Close(); } public void Close() { ... } } -- that way you get a public Close method, you don't see the potentially confusing Dispose method, and yet you can still use the object in a context where IDisposable is expected, like a "using" statement.

The "renaming" thing for Dispose/Close seems a bit unnecessary to me, and as for the "hide to discourage" argument, I lean to see its need as denoting a wrongly designed interface (and interface that can't properly fulfill its contract).

No comments:

Post a Comment