In the NORMA project we were encouraged to use Explicit Interface Method Implementation (EIMI). However, after reading a bit of Jeffrey Richter’s CLR via C#, I’ve decided to change the way I implement interfaces.
This entry is also a response to Ben’s blog entry, located here, which you should read first because it explains the difference between the two approaches.
Now…a little about why I disagree that EIMI should be used as often as possible.
- Having to cast an object to the interface just to call the interface method can get a little annoying in code. When you’re working on a team that might not be so familiar with this pattern then it takes extra time for them to get acquainted with it, because it’s a little awkward. However, this may be a superficial reason to some, so let’s continue…
- Regarding that cast, think about a case where you have a value type that has used EIMI to implement an interface. When you cast to the interface you burden your application by forcing a box operation on the value type so it can actually be treated as that interface type.
- Furthermore, with EIMI, if you derive from a class that implements an interface in this manner, you can’t call your base class’s implementation of that interface.
Now, I’m not saying that EIMI is useless. There are some specific cases when it is necessary. Take for instance the following example:
[code lang="csharp"] public interface IWindow
{
object GetMenu();
}
public interface IRestaurant
{
object GetMenu();
}
public class Pizzeria : IWindow, IRestaurant
{
object IWindow.GetMenu() { … }
object IRestaurant.GetMenu() { … }
}
[/code]
Here you have to use EIMI because you have two interfaces with the same method names. It doesn’t make sense to call GetMenu() and expect the CLR to infer which interface you’re binding to.
Another case where EIMI can come in handy is to improve compile-time safety. Let’s say you have a struct that implements a non-generic interface, like IComparable:
[code lang="csharp"] public interface IComparable
{
Int32 CompareTo(Object other);
}
public struct SomeValueType : IComparable
{
private int x;
public SomeValueType(Int32 x) { this.x = x; }
public Int32 CompareTo(Object other)
{
return x - ((SomeValueType)other).x;
}
}
// Now in some other method I can call CompareTo like this
public static void Main()
{
SomeValueType v = new SomeValueType(0);
Object o = new Object();
Int32 n = v.CompareTo(v); // Undesired Boxing
n = v.CompareTo(o); // InvalidCastException
}[/code]
So now instead of what’s listed above, you want to enforce some semblance of compile-time safety with your interface method. Here’s something you can do with EIMI:
[code lang="csharp"] public struct SomeValueType : IComparable
{
private int x;
public SomeValueType(Int32 x) { this.x = x; }
Int32 IComparable.CompareTo(Object other)
{
return CompareTo((SomeValueType)other);
}
public Int32 CompareTo(SomeValueType other)
{
return x - other.x;
}
}
// Now in some other method I can call CompareTo like this
public static void Main()
{
SomeValueType v = new SomeValueType(0);
Object o = new Object();
Int32 n = v.CompareTo(v); // No Boxing
n = v.CompareTo(o); // Compile-time Error
}[/code]
Of course, if we box SomeValueType into an IComparable instance then it would throw as above, so this s”olution” only alleviates the problem; in most cases your best bet would be to use a generic interface to enforce type-safety and remove boxing/unboxing operations.
Because of this, I have concluded that I will not use EIMI every chance I get, but instead will focus on using IIMI unless I really need to use EIMI as outlined by cases above.