Back to Blog
C#

C# Interface Implementation: Syntax and Patterns

c# interface implementation: Learn how to implement interfaces in C# with practical examples, including implicit and explicit implementation, default interface methods...

C# interfacesexplicit implementationdefault interface methodsdependency injectionabstraction
Illustration of a C# interface implementation showing a class connecting to an interface contract with method signatures.

c# interface implementation requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.

When you implement an interface in C#, you are committing to provide the members defined by that interface. The most common approach is implicit implementation, where you define a public member with the same signature as the interface member. For example:

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

Here, ConsoleLogger implements ILogger by providing a public Log method. This is the default style and works well when the class has no other member with the same name.

Implicit vs Explicit Interface Implementation

C# also supports explicit implementation, where you prefix the member name with the interface name. This is useful when you want to hide the member from the class's public API or when two interfaces declare members with identical signatures.

public interface IFileWriter { void Write(string content); } public interface IDatabaseWriter { void Write(string content); } public class Writer : IFileWriter, IDatabaseWriter { void IFileWriter.Write(string content) { // Write to file } void IDatabaseWriter.Write(string content) { // Write to database } }

In this example, both interfaces declare a Write method. Explicit implementation lets you provide separate logic for each. The methods are only accessible when the object is referenced through the respective interface type. Calling writer.Write(...) on a Writer instance will fail because the explicit implementations are not part of the class's public contract.

The choice between implicit and explicit implementation depends on how you intend the class to be used. Implicit implementation is simpler and makes the member available directly on the class. Explicit implementation is necessary when you need to disambiguate or when you want to prevent direct calls.

Handling Member Name Conflicts

When a class implements multiple interfaces that share member names, you have two options: provide a single implicit implementation that satisfies both, or use explicit implementations to give each interface its own behavior. The first approach works when the behavior is identical; the second is required when the behavior differs.

Consider a scenario where two interfaces both have a Connect method, but one is meant for a network connection and the other for a database connection. An implicit implementation would force you to choose one behavior, which may be incorrect for one of the interfaces. Explicit implementation avoids this by binding each method to its interface.

A less obvious conflict occurs when an interface member has the same name as an existing public method on the class. In that case, the implicit implementation will satisfy the interface, but you might inadvertently change the behavior of the existing method. Explicit implementation prevents this by keeping the interface method separate.

Default Interface Methods in C# 8+

Starting with C# 8, interfaces can include default implementations for their members. This allows you to add new members to an interface without breaking existing implementers. For example:

public interface IReport { string Generate(); string GenerateSummary() => Generate().Substring(0, 100); }

Classes that implement IReport only need to provide Generate. They can optionally override GenerateSummary if they want a custom summary. This feature is particularly useful when evolving public APIs in libraries.

However, default interface methods have a subtle behavior: they are not automatically available on the implementing class unless the class is accessed through the interface. If you have a class Report : IReport that does not override GenerateSummary, calling report.GenerateSummary() on a Report instance will not compile. You must cast to IReport first. This is because the default method is part of the interface, not the class.

Interface Inheritance and Composition

Interfaces can inherit from other interfaces, allowing you to build a hierarchy of contracts. For example:

public interface IRepository { void Add(object entity); } public interface IReadOnlyRepository { object GetById(int id); } public interface IReadWriteRepository : IRepository, IReadOnlyRepository { }

A class that implements IReadWriteRepository must implement all members from both base interfaces. This composition approach lets you define focused contracts and combine them as needed.

When designing interfaces, prefer composition over inheritance if you want to avoid forcing implementers to provide unrelated members. An interface that inherits too many members becomes a "fat" interface and is harder to implement correctly. Instead, split responsibilities into smaller interfaces and let classes implement only what they need.

Using Interfaces with Dependency Injection

Interfaces are central to dependency injection because they allow you to substitute implementations without changing the consuming code. For instance, a service class can depend on an IEmailSender rather than a concrete SmtpEmailSender. This makes the service testable and flexible.

public interface IEmailSender { void Send(string to, string subject, string body); } public class NotificationService { private readonly IEmailSender _emailSender; public NotificationService(IEmailSender emailSender) { _emailSender = emailSender; } public void Notify(string userEmail) { _emailSender.Send(userEmail, "Welcome", "Hello!"); } }

The implementation of IEmailSender can be registered in the dependency injection container and swapped for a mock during unit tests. This pattern is a direct benefit of interface implementation, and it is one of the main reasons interfaces are used in modern C# applications.

Performance and Design Considerations

Interface method calls are virtual calls, which means they have a small overhead compared to direct method calls. In most applications this overhead is negligible, but in hot paths you might notice it. If you are implementing a very performance-sensitive interface, consider whether an abstract class would be more appropriate. Abstract classes allow you to share implementation and use virtual methods, but they restrict inheritance to a single base class.

Another design consideration is the interface segregation principle. A class should not be forced to implement members it does not use. When you design an interface, keep it small and focused. If you find that an interface has many members, consider splitting it into multiple interfaces. This makes implementation easier and reduces the chance of throwing NotImplementedException for unused members.

Finally, remember that interfaces in C# do not contain fields, constructors, or static members (except for static abstract members in .NET 7+). They define a contract for instance members only. This constraint shapes how you design your abstractions and where you place shared logic.

c# interface implementation: Practical Usage and Code Exampl | RYUSLOG DEV