In C# 8 and later, we have default interface methods, so:
Doesn't it ruin the principle of interface?
When should we use default interface methods instead of base (abstract) class?
From a theoretical point of view, both interface implementation and class inheritance solve the same problem: They allow you to define a subtype relationship between types.
So why do we have both in C#? Why do we need interfaces at all? Can't we just define an interface as an abstract class, just as we do, for example, in C++?
The reason for this is the diamond problem: (Image source)
If both B
and C
implement A.DoSomething()
differently, which implementation should D
inherit? That's a hard problem, and the Java as well as the C# designers decided to avoid it by allowing multiple inheritance only for special base types which do not include any implementation. They decided to call these special base types interfaces.
So, there is no "principle of interface". Interfaces are just a "tool" to solve a particular problem.
Backwards compatibility. You wrote a vastly successful library used by thousands of developers worldwide. Your library contains some interface I
, and now you decide that you need an extra method M
on it. The problem is:
M
to I
, because that would break existing classes implementing I
(because they don't implement M
), andI
to an abstract base class, because that, as well, would break existing classes implementing I
, and you will lose the ability to do multiple inheritance.By not inheriting those default methods (example inspired by the one in this article, see the full article for some interesting corner cases):
interface I1
{
void M() { Console.WriteLine("I1.M"); } // default method
}
interface I2
{
void M() { Console.WriteLine("I2.M"); } // default method
}
class C : I1, I2 { }
class Program
{
static void Main(string[] args)
{
// c, i1 and i2 reference the same object
C c = new C();
I1 i1 = c;
I2 i2 = c;
i1.M(); // prints "I1.M"
i2.M(); // prints "I2.M"
c.M(); // compile error: class 'C' does not contain a member 'M'
}
}
Default interface methods are not inherited, but they are still virtual. Now, what does that mean? It means that a class can override the behavior of a default interface method:
interface I
{
void M() { Console.WriteLine("I.M"); } // default method
}
class C1 : I { }
class C2 : I
{
void I.M() { Console.WriteLine("C2.M"); }
}
class Program
{
static void Main(string[] args)
{
I i1 = new C1();
I i2 = new C2();
i1.M(); // prints "I.M"
i2.M(); // prints "C2.M"
}
}
You cannot do that with extension methods.