Default Interface Methods in C#
c# 8 allows developers to write a default implementation for the methods in the interfaces. I consider this feature as a high-risk language feature one as it can be easily misused that will lead to catastrophic code quality. In this article, we will discuss the correct use of this feature.
Before we get into the new feature method implementation in interfaces let’s get a quick introduction to the types of interfaces.
1- Header Interface
The header interface is similar to c++ header file usually it is extracted from a class by taking all the methods from the class and defining it in an interface, normally it is used to allow the developer to supply alternative implementations.
Example:
public interface IFileSystem
{File CreateFile(string filename);
void DeleteFile(string filename);
File GetFile(string filename);
}public class WindowsFileSystem:IFileSystem{// windows impl}public class LinuxFileSystem:IFileSystem{// Linux impl}
In this case, the IFileSystem interface only represents a contract that defines what a FileSystem Class Implementation should provide, and as it appears all these methods will have a very custom implementation.
but now let’s introduce a new Method named GetOrCreateFile this method simply searches if a file exists and returns it and in case it does not exist it will create a new one.
So our new method can be defined using the existing interface methods.
public File GetOrCreateFile(string filename)
{
var file=GetFile(filename);
if(file==null)
file=CreateFile(filename);
return file;}
And this implementation is valid for all FileSystems because it is abstract, so in this case, I would implement this method inside the Interface as a default method.
Interface vs Abstract Class
I am sure that people will be asking this question more now as the differences between both of them are reduced with the default method implementation feature.
So let’s first clarify something this question makes sense only with header interfaces as any header interface like IFileSystem can be replaced with a base class FileSystemBase. And if you think about multiple inheritance problem I can clearly say that
“A class cannot have more than one header interface and if so it should be considered an extreme violation to single responsibility principle”
please tweet it under hashtag #solid_principals
for a fast explanation of why this statement is a fact, Single responsibility means that a class should only have one reason for change and in case of header interface presence, the header interface will represent the high-level reason for the change think about “IFileSystem, IMediaManger, IRepository,….”
So back to our main question Header interface vs Abstract class. The answer is protected and private, an interface is just a contract for the class that tells the consumer what to expect from the class it cannot have it is own state and cannot force the class himself to have some kind of private state.
It is clear why in this case FileSystemBase must be a base class and cannot be an interface as GetFileCached handle the cache on it is own with a concrete implementation.
2- Roles Interface
Roles Interface is the optimum way for creating interfaces as it obeys the interface segregation principle, by contrast to Header interface which is a contract about all the functions that the class can provide, a role interface is a contract about what are the required functions that the class should implement in order to play a certain role.
public interface IFileWriter
{
File CreateFile(string filename);
void DeleteFile(string filename);
}public interface IFileReader
{
File GetFile(string filename);
List<File> GetFiles();
}
This is an example of how a Header Interface IFileSystem can be refactored to role interfaces IFileWriter and IFileReader.
The reason behind having only IFileWriter and IFileReader and not anything else is the consumer code so for example, I may need to consume this code
public class FilesListViewModel
{
public File Files { get; set; } public FilesListViewModel(IFileReader fileReader)
{
Files = fileReader.GetFiles();
} }public class FileCreatorViewModel
{
private readonly IFileWriter _fileWriter; public FileCreatorViewModel(IFileWriter fileWriter)
{
_fileWriter = fileWriter; } public void CreateNewFile(string name)
{
_fileWriter.CreateFile(name);
}
}
I cannot give you a general guidness about how you should design your code but I would suggest following the CQRS principle, back to the role interface a role interface is a role interface if it is created to satisfy the consumer needs like “IFileWriter, IFileReader” in the previous example or ICommand in the mvvm pattern and if you come from java background you will be familiar with the callback interface.
by contrast, to the Header interface, a class might need to implement multiple roles interfaces and here comes the famous say “Multiple Inheritance problem is solved by interface” I really like to modify this statement and to be
Multiple Inheritance is solved by interface but it should only be used with Role interface
please tweet it under hashtag #solid_principals
The default interface method can be used the same way as the Header interfaces like
public interface IFileWriter
{
File CreateFile(string filename);
void DeleteFile(string filename);public File CreateNew(string filename)
{
DeleteFile(filename);
CreateFile(filename);
}
}
but in some cases, you will find a default implementation that has cross roles dependencies like GetOrCreateFile() it requires both interfaces IFileReader and IFileWriter to be presented.
depend on the number of methods that has this cross roles dependencies problem you can decide if you need to merge both interfaces or introducing a union interface that implement these interfaces, for example,
public interface IFileSystem :IFileReader,IFileWriter
{
public File GetOrCreateFile(string filename)
{
var file = GetFile(filename); if (file == null)
file = CreateFile(filename); return file;
}
}
Bottom line Default Methods Implementation is a new feature that is game-changer, it will help build better software if it is used correctly but if it is abused it will destroy your code. In the upcoming articles, I show how useful it is with the decorator pattern and more about use cases.
so please follow me on twitter and on medium
and if you liked this article you can pay my coffee at
And you can learn more about c# from