Interfaces in C#
An INTERFACE in C# is a type definition similar to a class, except that it purely represents a contract between an object and its user. It can neither be directly instantiated as an object, nor can data members be defined. So, an interface is nothing but a collection of method and property declarations (C# Programming, emphasis mine)
Any vaguely experienced C# developer would understand and agree with the above definition. Interfaces are purely function signatures but do no contain any actual implementation.
public interface IFruit
{
void EatMe();
}
public class Apple : IFruit
{
public override void EatMe()
{
}
}
My confusion
I was recently helping some developers who are new to C# to learn some basic concepts. Among those concepts were interfaces and classes.
I came across the following interface that intuitively looks incorrect, but Visual Studio was not complaining and the code was building:
public interface IFruit
{
void EatMe();
int Sweetness
{
get
{
return 5;
}
}
}
What is going on here, why is it possible to add an implementation to an interface? You'll notice that the property is not returning a local variable value, but that's because the compiler does complain when you try to add those.
C# Default Interface Methods
The reason that this works is a new C# 8 feature called Default Interface Methods/Implementations. Developers can now add implementation details to an interface so that the implementing class doesn't need to. But why?
Picture the scenario:
- I write and publish a new library for managing fruit. At the time of publishing, I only considered that fruit would be eaten and so I created an interface like the one right at the top of this post.
- The library is wildly popular and I have many millions of users all implementing my
IFruit
interface in their extremely important line of business apps. - I've received a lot of feedback from my users that they need some way to check the sweetness of the fruit before deciding whether to eat it or not, so I decide to add a
Sweetness
property. - Awesome, I'm such a responsive, caring library maintainer. I push out the change and wait for the thank you emails...
- I get them from a few people (those that asked for Sweetness), but the majority of my emails are from everyone else who doesn't care about sweetness, but who's super critical software no longer builds because they have not implemented this silly property. 😮
Enter C# 8 and this new Default Interface Implementations feature which were added for this exact reason. They allow you to:
1. Add private static member variables
1. Add default implementations for properties defined on the interface
1. Add default implementations for methods defined on the interface
Using these features, I would be able to add my Sweetness
property without affecting users of my library who didn't care.
public interface IFruit
{
void EatMe();
private static int _defaultSweetness;
int Sweetness
{
get
{
return _defaultSweetness;
}
set
{
//do nothing
}
}
void SweetEnoughToEat(int desiredSweetness)
{
return Sweetness >= desiredSweetness;
}
}
But, but this just feels wrong
I feel you, it does feel wrong but it also feels like an elegant solution to a real problem. That being said, it's probably not a problem that we encounter in our regular projects. My advice: know it exists for the case when you'll need it, but don't abuse it by giving all interfaces default implementations, that's what abstract classes exist for.