C# interfaces are a powerful feature of the C# programming language that allow developers to define a contract for the behavior of objects without specifying the implementation details. An interface is a collection of method and property signatures that define a set of behaviors that a class can implement. This allows classes to provide common functionality without being tied to a specific implementation, making it easier to write reusable and maintainable code.
In object-oriented prognarmming languages, Interfaces are used to define contracts for communication between multiple components. C# interfaces can be thought of as a blueprint for a class. This means that the class must provide the methods and properties defined in the interface. Any class that implements an interface can be used in place of any other class that implements that interface.
Syntax of C# Interfaces
Here is the basic syntax of a C# interface:
1 2 3 4 5 6 7 8 |
interface InterfaceName { // Method signatures returnType MethodName(parameterList); // Property signatures returnType PropertyName { get; set; } } |
The interface keyword is used to define an interface, followed by the interface name. The interface can then include method signatures and property signatures. Method signatures are defined with the method return type, followed by the method name and parameter list. Property signatures are defined with the property return type and optional getter and setter methods.
Example of C# Interfaces
Here is an example of an interface in C#:
1 2 3 4 5 |
interface IAnimal { string Name { get; set; } void Speak(); } |
This interface defines two members: a property called Name
and a method called Speak
. Any class that implements this interface must provide an implementation for both the Name
property and the Speak
method.
Here is an example of a class that implements this interface:
1 2 3 4 5 6 7 8 9 |
class Dog : IAnimal { public string Name { get; set; } public void Speak() { Console.WriteLine("Woof!"); } } |
This class defines a property called Name
and a method called Speak
, both of which adhere to the interface definition in IAnimal
. The class can be used anywhere an IAnimal
is expected, which allows for greater flexibility and code reuse. If you want to skyrocket your C# career, check out our powerful ASP.NET full-stack web development course that also covers test-driven development.
Dependency Injection
Dependency injection is a technique that allows objects to be created and configured at runtime rather than at compile time. Interfaces are often used to define dependencies in this context. For example, a class that requires a database connection might take an IDatabaseConnection
interface as a constructor parameter. This allows different database implementations to be swapped in and out without affecting the class that uses them (the interface’s client).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
interface IDatabaseConnection { void Connect(); void Disconnect(); } class SqlDatabaseConnection : IDatabaseConnection { public void Connect() { // Connect to SQL Server } public void Disconnect() { // Disconnect from SQL Server } } class SomeClass { private readonly IDatabaseConnection _connection; public SomeClass(IDatabaseConnection connection) { _connection = connection; } public void DoSomething() { _connection.Connect(); // Do something with the database _connection.Disconnect(); } } |
In this example, the SomeClass
constructor takes an IDatabaseConnection
interface as a parameter. This allows different implementations of the IDatabaseConnection
interface to be passed in at runtime. The SqlDatabaseConnection
class is one such implementation.
Testing
Interfaces are often used in testing to provide “mock” implementations of classes. A mock object is a substitute for a real object that can be used in testing. Mock objects are often used when the real object is difficult to create or configure, such as when it requires access to a database or external system. By defining an interface for the real object, a mock object can be created that adheres to the same interface and can be used in place of the real object in tests.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
interface IOrderRepository { void SaveOrder(Order order); } class OrderService { private readonly IOrderRepository _orderRepository; public OrderService(IOrderRepository orderRepository) { _orderRepository = orderRepository; } public void PlaceOrder(Order order) { // Do something with the order _orderRepository.SaveOrder(order); } } class MockOrderRepository : IOrderRepository { bool SaveOrderCalled = false; public void SaveOrder(Order order) { this.SaveOrderCalled = true; } } [Test] public void PlaceOrder_Should_Save_Order_To_Repository() { var mockRepository = new MockOrderRepository(); var orderService = new OrderService(mockRepository); var order = new Order(); orderService.PlaceOrder(order); Assert.That(mockRepository.SaveOrderCalled, Is.True); } |
In this example, the OrderService
class takes an IOrderRepository
interface as a constructor parameter. A mock implementation of this interface is created for use in testing. The test checks that the SaveOrder
method is called when the PlaceOrder
method is called.
Polymorphism
Polymorphism is the ability of objects to take on multiple forms. Interfaces allow for polymorphism by defining a common set of behaviors that can be shared among different classes. This allows for greater flexibility and code reuse.
For example, consider a drawing application that allows users to draw different shapes. The application might define an IShape
interface that all shapes must adhere to. This allows different shapes to be drawn using a common set of methods and properties.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
interface IShape { void Draw(); } class Circle : IShape { public void Draw() { // Draw a circle } } class Square : IShape { public void Draw() { // Draw a square } } class DrawingApplication { private readonly List<IShape> _shapes = new List<IShape>(); public void AddShape(IShape shape) { _shapes.Add(shape); } public void DrawShapes() { foreach (var shape in _shapes) { shape.Draw(); } } } |
In this example, the Circle
and Square
classes implement the IShape
interface. The DrawingApplication
class takes a list of IShape
objects and can draw them all using the DrawShapes
method. By the way, did you know that we offer a unique online course that boosts your C# career? Check it out here!
Conclusion
C# interfaces are a powerful tool that can be used to create reusable, flexible, and maintainable code. They allow developers to define a contract for the behavior of objects without specifying the implementation details. This makes it easier to write code that can be reused in different contexts and to swap out implementations of objects at runtime. Interfaces are used in many scenarios, such as dependency injection, testing, and polymorphism. By mastering the use of interfaces in C#, developers can write code that is more flexible, more maintainable, and more powerful. You can also see a comparison between interfaces and abstract classes here.