With the release after release C# 8.0, several exciting features were introduced to improve developer productivity and code clarity. One of these features is default interface methods or interface method definitions with bodies. This enhancement allows developers to define a method's body directly in an interface, a feature that brings interfaces closer in behavior to abstract classes while maintaining their core purpose.
Understanding Interfaces in C#
Traditionally, interfaces in C# only allowed method declarations—a method signature without any implementation. Classes or structs implementing the interface were responsible for providing the implementation. For example:
public interface IShape
{
void Draw(); // No body allowed
}
public class Circle : IShape
{
public void Draw()
{
Console.WriteLine("Drawing a Circle");
}
}
This approach enforces consistency among implementing types but also introduces some limitations. If you wanted to add a new method to the interface, you would have to update all implementing classes, even if they shared a common implementation.
Default Interface Methods After C# 8.0
Default interface methods provide a way to define a method's body within an interface. This enables you to add new methods to an interface without breaking existing implementations. Any class or struct that implements the interface will automatically inherit the default behavior unless it explicitly overrides it.
Syntax
To define a default interface method, you simply include the method implementation in the interface:
public interface IShape
{
void Draw();
// Default method with implementation
void Resize()
{
Console.WriteLine("Resizing the shape by default logic");
}
}
Example: Default Interface Method in Action
Here’s a practical example:
public interface IShape
{
void Draw();
// Default implementation for Resize
void Resize()
{
Console.WriteLine("Default resizing logic applied.");
}
}
public class Circle : IShape
{
public void Draw()
{
Console.WriteLine("Drawing a Circle");
}
}
public class Square : IShape
{
public void Draw()
{
Console.WriteLine("Drawing a Square");
}
// Overriding the default Resize behavior
public void Resize()
{
Console.WriteLine("Custom resizing logic for Square.");
}
}
public class Program
{
public static void Main()
{
IShape circle = new Circle();
circle.Draw();
circle.Resize(); // Uses default implementation
IShape square = new Square();
square.Draw();
square.Resize(); // Uses custom implementation
}
}
Output
Drawing a Circle
Default resizing logic applied.
Drawing a Square
Custom resizing logic for Square.
Key Benefits
Backward Compatibility: You can extend an interface without forcing changes to existing implementations.
Code Re-usability: Shared logic can be implemented directly in the interface.
Flexibility: Implementing classes can either use the default behavior or provide a custom implementation.
Considerations and Limitations
Interface Purpose: The primary purpose of an interface is to define a contract. Adding method bodies blurs the line between interfaces and abstract classes.
Dependency Injection: Default methods can introduce complications in scenarios where dependency injection relies on strict interface contracts.
Versioning Challenges: Care must be taken when updating default implementations in libraries to avoid unintended consequences for existing consumers.
Conclusion
Default interface methods after release C# 8.0 are a powerful addition that balances flexibility and compatibility. They enable developers to evolve interfaces more gracefully while reducing boilerplate code. However, they should be used judiciously to maintain the clarity and purpose of interfaces in object-oriented design.