If a class implements two interfaces that contain a member with the same signature, then implementing that member on the class will cause both interfaces to use that member as their implementation. For example:
What are good reasons to use explicit interface implementation for the sole purpose of hiding members?
Explicit Interface Implementations in C#
June 25, 2008
Well, you learn something new every day. Although explicit interface implementations are fairly common when you are implementing two interfaces with conflicting (ie, the same) member signatures, they can also be used to “hide” a interface member.
While working with the RegistryKey class today, I noticed that even though it implements IDisposable, it does not publicly expose Dispose(). Read on to find out why.
We start with a general discussion of explicit interface implementations. Suppose you have the following two interfaces:
Then, in the following class, both Foo.Hello and Bar.Hello will call this classes implementation of Hello:
And of course, if we wanted separate implementations for Foo.Hello and Bar.Hello we would do:
Now, notice that the public access modifier is no longer present. Try putting the public access modifer in, and you’ll get an error: The modifier ‘public’ is not valid for this item. This is because if Baz exposed Hello publicly, it wouldn’t be clear which Hello was to be called. And indeed, you can’t simply call Hello() on an instance of Baz, you have to cast it to Foo or Bar first:
OK, so this is all pretty basic and most C# developers will be aware of all this. Most people will have stumbled across it by necessity.
So now I look at the lesser known property of explicit interface implementations: used to “hide” interface implementations that aren’t in conflict.
You may be surprised to know that if you remove the inheritance from, say, Bar in the above class, the thing will still compile:
Moreover, when you try to do something like this:
You’ll receive an error: “‘Baz’ does not contain a definition for ‘Hello’”. You’ll notice that we don’t provide the public access modifier to Foo.Hello in our Baz class, so of course we get such an error. So it turns out that you can essentially hide interface members of a class. From the Implementing Interface Members Explicitly documentation on MSDN:
But not:
So why would you want to do this? Well, the documentation cited before also states:
While working with the RegistryKey class today, I noticed that even though it implements IDisposable, it does not publicly expose Dispose(). Read on to find out why.
We start with a general discussion of explicit interface implementations. Suppose you have the following two interfaces:
- interface Foo {
- void Hello();
- }
- interface Bar {
- void Hello();
- }
- class Baz : Foo, Bar {
- public void Hello() {
- /* do something here. */
- }
- }
- class Baz : Foo, Bar {
- void Foo.Hello() {
- /* do something here. Called by Foo.Hello */
- }
- void Bar.Hello() {
- /* do something here. Called by Bar.Hello */
- }
- }
- void SomeFunction() {
- Baz b = new Baz();
- b.Hello(); /* ERROR: will not compile */
- ((Foo)b).Hello(); /* Calls Foo.Hello */
- ((Bar)b).Hello(); /* Calls Bar.Hello */
- }
So now I look at the lesser known property of explicit interface implementations: used to “hide” interface implementations that aren’t in conflict.
You may be surprised to know that if you remove the inheritance from, say, Bar in the above class, the thing will still compile:
- class Baz : Foo {
- void Foo.Hello() {
- /* do something here. Called by Foo.Hello */
- }
- }
- void SomeFunction() {
- Baz b = new Baz();
- b.Hello(); /* ERROR: will not compile */
- }
When an interface member is explicitly implemented by a class, the member can be accessed only by using a reference to the interface. This has the effect of hiding the interface memberIt turns out that this is what RegistryKey() does with IDisposable.Dispose(). Dispose() is hidden by using explicit interface implementations. So you can do the following:
- void SomeFunction(RegistryKey key) {
- ((IDisposable)key).Dispose();
- }
- void SomeFunction(RegistryKey key) {
- key.Dispose();
- }
Consider implementing interface members explicitly to hide a member and add an equivalent member with a better name.I guess this was the intention with RegistryKey. It seems to me, however, that this reasoning is a bit silly. Dispose, according to MSDN, “performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.” Isn’t this what we want to happen when we are done with a RegistryKey instance? I would suggest that the member with the “better name” here is Dispose, not close. If we’re working in the .NET paradigm, we should stick to Dispose. Many classes could then avoid the need to have Close() at all, and ensure that novice .NET developers are exposed to IDisposable more often. Alas, it is not the case.
This effectively renames a member. For example, Stream implements Dispose explicitly and provides the Close method in its place.
Comments
Post a Comment