C# 8.0 introduced default interface members, allowing interfaces to include method bodies. This enables API evolution without forcing every existing implementation to update at once.
Why it matters
- Helps library authors add functionality without immediate breaking changes.
- Supports gradual migrations where implementations can override when ready.
- Keeps shared fallback behavior close to the interface contract.
Cautions
Use default members for compatibility, not as a replacement for solid abstraction design. Overusing defaults can hide too much behavior in interfaces and make implementations harder to reason about.
Add default behavior to an interface
Default members let existing implementations keep working when an interface evolves.
Valid since C# 8.0
using System;
public interface ITemperatureFormatter
{
string FormatCelsius(double celsius) => celsius.ToString("0.0") + " C";
}
public class BasicFormatter : ITemperatureFormatter
{
}
public static class Program
{
public static void Main()
{
Console.WriteLine(((ITemperatureFormatter)new BasicFormatter()).FormatCelsius(21.34));
}
}
Override interface default behavior
Implementations can still provide custom behavior when needed.
Valid since C# 8.0
using System;
public interface ITemperatureFormatter
{
string FormatCelsius(double celsius) => celsius.ToString("0.0") + " C";
}
public class FancyFormatter : ITemperatureFormatter
{
public string FormatCelsius(double celsius) => celsius.ToString("0.00") + " °C";
}
public static class Program
{
public static void Main()
{
Console.WriteLine(((ITemperatureFormatter)new FancyFormatter()).FormatCelsius(21.34));
}
}
Related features
Learn more
Default interface methods versioning tutorial (Microsoft Learn)