Explanation of how interface inheritance is implemented in .NET, and how to properly use it in C#.
I have had a little debate not long ago about pros and cons of interface inheritance in .NET C# language. It may be worth restating the main points of the discussion.
Definition from C# language specification: (http://msdn.microsoft.com/en-us/library/aa664578(VS.71).aspx)
An interface can inherit from zero or more interfaces, which are called the explicit base interfaces of the interface
Example: per definition above IComboBox inherits ITextBox, IListBox, and indirectly IControl interfaces. The official definition notwithstanding, note that you can also say the IComboBox implements the same interfaces without violating the meaning and implications of the resulting relationship.
interface IControl
{
void Paint();
}
interface ITextBox: IControl
{
void SetText(string text);
}
interface IListBox: IControl
{
void SetItems(string[] items);
}
interface IComboBox: ITextBox, IListBox {}
Next is interface implementation. A class can
implement an interface. Unfortunately, in C# unlike VB and Java, the syntax for inheritance and implementation is the same, i.e. the syntax simply uses “:” operator. Result – lots of confusion.
interface IMyInterface {}
class MyClass : IMyInterface {}
The difference becomes a little clearer when you consider this example:
public interface IMyBaseInterface
{
void DoA();
}
public interface IMyDerivedInterface : IMyBaseInterface
{
void DoB();
}
public class MyClass : IMyDerivedInterface
{
void DoA();
void DoB();
}
The result of MyClass explicitly implementing IMyDerivedInterface is that it implicitly got saddled with a requirement to also explicitly implement IMyBaseInterface.
“So. What exactly is the problem?” After all, Microsoft is using interface inheritance in .NET framework for ICollection : IEnumerable definition and the like. Here are my objections to the interface inheritance practice on a broad scale:
- Interfaces are contracts. Implicit contracts are like a programming fine print. An interface is a pure definition and always requires a class to implement the declared contract behavior. Per the example above, MyClass indirectly realizes the contract IMyBaseInterface behavior, but has to explicitly implement it nonetheless. A better practice is simply for IMyDerivedInterface not to inherit IMyBaseInterface and for MyClass to explicitly implement both IMyDerivedInterface and IMyBaseInterface interfaces. The result is the same without the “fine print” contract. This way, another class wanting to implement only IMyDerivedInterface would not be forced into implementing DoA() of IMyBaseInterface interface.
public interface IMyBaseInterface
{
void DoA();
}
public interface IMyDerivedInterface
{
void DoB();
}
public class MyClass : IMyDerivedInterface, IMyBaseInterface
{
void DoA();
void DoB();
}
Interface inheritance practice contradicts polymorphism through interface implementation that emphasizes using a single interface behavior to interact with objects of different types that implement it. From the previous example, interface IMyBaseInterface is always implicitly dragged into every implementation for every type that is simply trying to implement only IMyDerivedInterface methods. This is no longer a single behavior for a single interface.
Interface inheritance practice leads to unnecessary code duplication instead of code reuse. Even in a case of ICollection : IEnumerable interface definition, I wonder if such tacking on of IEnumerable contract was necessary. In a perfect world, one would be better off inheriting from an abstract class or a class that has IEnumerable rudimentary implementation once: i.e. the showcase of reuse with inheritance. I am not completely opposed to interface inheritance. Even ICollection : IEnumerable may have additional valid considerations I am missing. However, on a broad scale, interface inheritance adds more contract “fine print” and forces potentially unnecessary implementation and code duplication.
Interface is a contractual constraint. It has no behavior of its own, and thus, produces no value of its own. Interface inheritance makes the contractual constraint on an implementing class even more convoluted, but still produces no value of its own: all interfaces in the inheritance tree still need a class to produce any value.
Finally, in spite of C# interface inheritance definition and terminology in the C# language spec, .NET framework compiles all interface “inheritance” definitions as interface implementation. For example, the compiled ICollection : IEnumerable interface definition is interpreted as ICollection implements IEnumerable, not inherits. That is true for generics too. You can the example below for yourself:
Upon the breakpoint, check ic variable, and note the BaseType value:
Now check the result of ic.GetInterfaces():
This is a long way to say: interfaces are to be implemented, not inherited from. Do not use interface inheritance unless it is unavoidable, and by “unavoidable” I mean “almost never”.