Interfaces are a way to define a common interface which many classes can implement without having to inherit from a base class. They do, however, suffer from the limitation that once implemented any future changes to the interface will break all implementing classes. Sometime this can be avoided using extension methods.
C# 8.0 allows interfaces to provide default implementations of methods that can be overridden by implementing classes allowing the interface to evolve over time.
Code
C#
interface ILogger
{
void Log(LogLevel level, string message);
void Warn(string message) => Log(LogLevel.Warning, message);
}
class ConsoleLogger : ILogger
{
public void Log(LogLevel level, string message) => Console.WriteLine(level + " " + message);
}
C#
interface ILogger
{
void Log(LogLevel level, string message);
}
// It's either this or a breaking change...
interface ILogger2 : ILogger
{
void Warn(string message);
}
class ConsoleLogger : ILogger2
{
public void Log(LogLevel level, string message) => Console.WriteLine(level + ": " + message);
public void Warn(string message) => Console.WriteLine("Warning: " + message);
}
C#
interface ILogger
{
void Log(LogLevel level, string message);
}
static class LogExtensions
{
public void Warn(this ILogger logger, string message) => logger.Log(LogLevel.Warning, message);
}
class ConsoleLogger : ILogger
{
public void Log(LogLevel level, string message) => Console.WriteLine(level + ": " + message);
}
Notes
- This functionality is familiar as the
trait
feature in other languages such as Rust and Scala.