C# tutorials > Modern C# Features > C# 6.0 and Later > What are default interface methods and how can they be used?

What are default interface methods and how can they be used?

Default interface methods, introduced in C# 8.0, allow you to add methods to an interface without breaking existing classes that implement the interface. This provides a powerful way to evolve interfaces over time without forcing all implementing classes to immediately implement the new methods.

The Basics of Default Interface Methods

In this example, ILogger defines two methods: Log and LogInformation. The LogInformation method has a default implementation. Any class implementing ILogger is required to implement Log, but it can choose to use the default implementation of LogInformation or provide its own.

public interface ILogger
{
    void Log(string message);

    // Default implementation of a new method
    void LogInformation(string message)
    {
        Log($"Information: {message}");
    }
}

Implementing the Interface

ConsoleLogger implements the ILogger interface. It provides its own implementation for Log. It does not need to explicitly implement LogInformation because a default implementation is provided in the interface. If ConsoleLogger needs to customize the behavior of LogInformation, it can override it.

public class ConsoleLogger : ILogger
{
    public void Log(string message)
    {
        Console.WriteLine(message);
    }

    // Can choose to override LogInformation or use the default implementation
}

Overriding the Default Implementation

FileLogger also implements ILogger. It provides its own implementation for Log and overrides the default implementation of LogInformation. This demonstrates how a class can customize the behavior of a default interface method.

public class FileLogger : ILogger
{
    private readonly string _filePath;

    public FileLogger(string filePath)
    {
        _filePath = filePath;
    }

    public void Log(string message)
    {
        File.AppendAllText(_filePath, message + Environment.NewLine);
    }

    // Override the default implementation
    public void LogInformation(string message)
    {
        Log($"File Information: {message}");
    }
}

Calling Default Interface Methods

This code shows how to use the ILogger interface with both ConsoleLogger and FileLogger. The LogInformation method is called on both instances, demonstrating that it uses the default implementation for ConsoleLogger and the overridden implementation for FileLogger.

ILogger logger = new ConsoleLogger();
logger.Log("This is a log message.");
logger.LogInformation("This is an information message.");

ILogger fileLogger = new FileLogger("log.txt");
fileLogger.Log("Another log message.");
fileLogger.LogInformation("Another information message.");

Concepts Behind the Snippet

The core concept behind default interface methods is to provide a mechanism for interface evolution. Before C# 8.0, adding a new method to an interface would be a breaking change, requiring all implementing classes to be modified. Default interface methods provide a way to add new functionality to an interface without forcing immediate changes to all implementations.

It's crucial to understand that the default implementation resides within the interface itself. This avoids code duplication across implementations and promotes code reuse. However, the inheriting class always has the option to override the default implementation if needed.

Real-Life Use Case

Imagine you have a large library with an interface that many third-party developers have implemented. You want to add a new feature to the interface without breaking existing implementations. Using default interface methods, you can provide a default implementation that satisfies most use cases, while allowing developers to override it if they need custom behavior. This is far superior to introducing a completely new interface and deprecating the old one. Another real-world example is in the evolution of the .NET framework itself. Default interface methods allow Microsoft to add new methods to existing interfaces without breaking backwards compatibility.

Best Practices

  • Use Sparingly: Default interface methods should be used judiciously. Overuse can lead to complex interfaces and make it harder to understand the responsibilities of implementing classes.
  • Simple Implementations: Keep default implementations simple and generic. If the default implementation requires complex logic or depends on specific state, it's likely better to require implementations to provide their own behavior.
  • Consider Abstract Classes: If you find yourself adding multiple default implementations, consider using an abstract class instead. Abstract classes offer more flexibility in terms of state and behavior.
  • Document Clearly: Clearly document the purpose of default interface methods and when they should be overridden.

Interview Tip

When discussing default interface methods in an interview, emphasize that they are a mechanism for interface evolution and backward compatibility. Explain the tradeoffs involved and the scenarios where they are most appropriate. Be prepared to discuss the potential for code complexity if overused and the alternative of using abstract classes.

When to Use Them

Use default interface methods primarily when:

  • You need to add functionality to an existing interface without breaking existing implementations.
  • You want to provide a reasonable default implementation for a method.
  • The default implementation is relatively simple and doesn't rely on complex state or behavior.

Memory Footprint

Default interface methods don't add significant overhead. The default implementation lives in the interface definition and is used only when an implementing class doesn't provide its own. This avoids duplicating code across multiple implementations.

Alternatives

Alternatives to default interface methods include:

  • Abstract Classes: Abstract classes can provide default implementations and state, but they require inheritance, which limits flexibility.
  • Extension Methods: Extension methods can add new methods to an interface, but they cannot be overridden by implementing classes and do not become part of the interface contract.
  • Creating a New Interface: Introduce a new interface. Existing classes won't implement it, but new ones can. This might cause some confusion.

Pros

  • Backward compatibility.
  • Code reuse by providing default implementations.
  • Interface evolution without breaking changes.

Cons

  • Can lead to complex interfaces if overused.
  • Can make it harder to understand the responsibilities of implementing classes.
  • Limited in terms of state management compared to abstract classes.

FAQ

  • Can I have multiple default interface methods in an interface?

    Yes, an interface can have multiple default interface methods.

  • Can a class override a default interface method and then call the base (interface) implementation?

    Yes, a class can override a default interface method and call the base (interface) implementation using the base keyword qualified with the interface name. For example: ((IMyInterface)this).MyMethod();

  • Are default interface methods supported in all C# versions?

    No, default interface methods were introduced in C# 8.0 and require a compatible .NET runtime.