Interfaces in C# define a contract that classes and structs can implement. An interface says what members a type must provide, but it does not usually care how those members are implemented. This makes interfaces one of the most important tools for writing flexible and testable C# code.
Interfaces are heavily used in modern C# applications. They appear in dependency injection, repositories, services, logging, testing, collections, APIs, plugins, and framework design. When code depends on an interface instead of a concrete class, it becomes easier to replace one implementation with another.
An interface is not mainly about code reuse. It is about behavior contracts. If a class implements an interface, it promises that it can perform the operations described by that interface.
What Is Interface in C#?
An interface is a type that defines members such as methods, properties, events, and indexers. A class that implements the interface must provide those members.
interface ILogger
{
void Log(string message);
}
class ConsoleLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine(message);
}
}
The ILogger interface defines a contract. The ConsoleLogger class implements that contract by providing the Log method.
Interface Syntax in C#
interface InterfaceName
{
returnType MethodName(parameters);
}
By convention, interface names in C# usually start with the letter I, such as IRepository, IService, ILogger, and IDisposable.
Implementing an Interface
A class implements an interface by using the colon symbol. The class must provide public implementations for the interface members.
interface IShape
{
double GetArea();
}
class Circle : IShape
{
public double Radius { get; set; }
public double GetArea()
{
return Math.PI * Radius * Radius;
}
}
The Circle class implements IShape, so it must provide the GetArea method. If it does not, the code will not compile.
Using Interface References
Once a class implements an interface, an object of that class can be stored in a variable of the interface type. This enables polymorphism.
IShape shape = new Circle { Radius = 5 };
Console.WriteLine(shape.GetArea());
The variable type is IShape, but the actual object is Circle. Code using the interface does not need to know the exact class. It only needs the behavior promised by the interface.
Multiple Interfaces in C#
C# does not support multiple inheritance with classes, but a class can implement multiple interfaces. This is useful when a type has multiple capabilities.
interface IPrintable
{
void Print();
}
interface IScannable
{
void Scan();
}
class PrinterScanner : IPrintable, IScannable
{
public void Print()
{
Console.WriteLine("Printing document");
}
public void Scan()
{
Console.WriteLine("Scanning document");
}
}
The class promises that it can print and scan. Each interface describes one capability, which keeps the design clean.
Interface Properties in C#
An interface can define properties. The implementing class must provide those properties with compatible accessors.
interface IUser
{
string Name { get; set; }
string Email { get; }
}
class User : IUser
{
public string Name { get; set; }
public string Email { get; private set; }
public User(string name, string email)
{
Name = name;
Email = email;
}
}
The interface requires Name to be readable and writable. It requires Email to be readable. The class can still use a private setter internally because the public contract only requires a getter.
Interface Methods in C#
Methods are the most common members in interfaces. They describe actions that implementing classes must provide.
interface INotificationSender
{
void Send(string receiver, string message);
}
class EmailSender : INotificationSender
{
public void Send(string receiver, string message)
{
Console.WriteLine($"Email sent to {receiver}: {message}");
}
}
class SmsSender : INotificationSender
{
public void Send(string receiver, string message)
{
Console.WriteLine($"SMS sent to {receiver}: {message}");
}
}
Both classes follow the same interface, but each class sends the notification differently. This is a practical example of interface-based polymorphism.
Interfaces and Dependency Injection
Dependency injection commonly uses interfaces. A class depends on an interface, and the application provides the actual implementation at runtime. This keeps the class loosely coupled.
class AccountService
{
private readonly INotificationSender sender;
public AccountService(INotificationSender sender)
{
this.sender = sender;
}
public void CreateAccount(string email)
{
sender.Send(email, "Account created successfully");
}
}
AccountService does not depend on EmailSender directly. It depends on INotificationSender. This makes testing and replacement easier.
Explicit Interface Implementation
Explicit interface implementation is used when a class implements an interface member in a way that can only be accessed through the interface type. This is useful when two interfaces have members with the same name or when the member should not appear as part of the normal public class API.
interface IReport
{
void Print();
}
class SalesReport : IReport
{
void IReport.Print()
{
Console.WriteLine("Printing sales report");
}
}
IReport report = new SalesReport();
report.Print();
The Print method is available through the IReport reference. It is not called directly on a SalesReport variable unless the object is cast to the interface.
Interfaces vs Abstract Classes
| Point | Interface | Abstract Class |
|---|---|---|
| Purpose | Defines a behavior contract | Provides a common base with shared logic |
| Multiple use | A class can implement many interfaces | A class can inherit only one class |
| State | Usually no instance state | Can contain fields and shared state |
| Best use | Capability or role | Common base type with shared implementation |
Use an interface when you want to define what a type can do. Use an abstract class when related classes need shared code, shared state, or a common base implementation.
Real World Uses of Interfaces
IDisposablefor cleanup logic.IEnumerablefor iteration support.- Repository interfaces for database access.
- Service interfaces for business logic.
- Logger interfaces for replaceable logging implementations.
- Payment gateway interfaces for multiple payment providers.
Interfaces let code depend on behavior instead of a specific class. This is a major part of writing maintainable applications.
Default Interface Methods
Modern C# supports default interface methods. This means an interface can provide a default implementation for a member. This feature is useful for evolving interfaces without immediately breaking every implementing class.
interface IAudit
{
void Save();
void LogAudit()
{
Console.WriteLine("Audit log written");
}
}
Even though this feature exists, it should be used carefully. Interfaces are still best when they describe clean contracts. Too much logic inside interfaces can make the design harder to understand.
Common Mistakes with Interfaces
- Creating interfaces with only one implementation and no real abstraction need.
- Making interfaces too large and forcing classes to implement unused members.
- Using vague names such as
IManagerorIHelper. - Putting unrelated responsibilities into one interface.
- Using interfaces to hide poor class design instead of improving the design.
A good interface should be small, focused, and meaningful. If an interface has too many methods, it may be better to split it into smaller role-based interfaces.
Best Practices for Interfaces in C#
- Name interfaces clearly using the
Iprefix convention. - Design interfaces around behavior, not storage details.
- Keep interfaces small and focused.
- Use interfaces for replaceable implementations.
- Depend on interfaces in services when it improves testing or flexibility.
- Avoid creating interfaces automatically for every class.
Interfaces and Testing
Interfaces make testing easier because a test can provide a fake or mock implementation. For example, a class that depends on IEmailSender can be tested without sending a real email. The test only needs an object that follows the same interface contract.
Interface Design Rule
A strong interface should describe a capability from the caller’s point of view. For example, INotificationSender is clearer than IEmailServiceHelper because it explains the behavior, not the internal technology. If the caller only needs to send notifications, it should not care whether the implementation uses email, SMS, push notification, or another provider.
This is why interfaces are useful in layered applications. Controllers can depend on service interfaces, services can depend on repository interfaces, and tests can replace those interfaces with in-memory versions. The code becomes easier to change because dependencies point toward contracts instead of concrete details.
Interface Interview Points
For interviews, remember that a class can implement multiple interfaces but inherit from only one class. Interface members are usually implemented as public members in the class. Interfaces support polymorphism because different classes can be used through the same interface reference.
Also remember that interfaces are best for defining capabilities. Abstract classes are better when you need shared state or shared base implementation. Interfaces and abstract classes are not enemies; they solve different design problems.
Interface Segregation in C#
Interface segregation means a class should not be forced to implement members it does not need. Instead of one large interface with many unrelated methods, create smaller interfaces that represent focused capabilities. This makes code cleaner because each class implements only what it actually supports.
interface IPrinter
{
void Print();
}
interface IScanner
{
void Scan();
}
A simple printer can implement only IPrinter. A multi-function device can implement both IPrinter and IScanner. This is better than forcing every device to implement one large interface with methods it cannot support.
Small interfaces also make testing easier. A test double only needs to implement the behavior required by the code under test, not a large unrelated contract. This keeps tests simple and prevents fake classes from becoming unnecessarily complicated.
When an interface stays focused, both production classes and test classes remain easier to read, replace, and maintain over time in real C# application projects.
FAQs on Interfaces in C#
Can a class implement multiple interfaces in C#?
Yes. A class can implement multiple interfaces. This is commonly used when a class supports multiple capabilities.
Can an interface have properties?
Yes. Interfaces can define properties, methods, events, and indexers. The implementing class must provide compatible members.
What is the difference between interface and abstract class?
An interface defines a contract or capability. An abstract class can provide shared code, shared state, and a common base for related classes.
Why are interfaces useful in testing?
Interfaces allow tests to provide fake or mock implementations, so code can be tested without depending on real databases, APIs, files, or external services.