An interface in C# is a type which only defines a group of related functionalities and leaves the implementation of the functionalities to any class or struct which implements the interface. It helps a lot in implementing the SOLID principles and makes the application more decoupled. It also can help us in achieving multiple inheritances, given the fact that this cannot be done in C# using only classes.
How to implement an Interface in a class
The syntax is simple,
- interface interface_name
- {
-
- }
- class class_name : interface_name
- {
- ---------------------
-
- ---------------------
- }
Let’s see an example. I created a console application InterfacesWithSameSignature.
- Renamed class1.cs to InterfaceExample.cs.
- Removed the default class and added an interface ISampleInterface.
- Added a method - MySampleMethod() to the interface.
- public interface ISampleInterface
- {
- void MySampleMethod();
- }
Note
It is standard practice to start the name of the interface with "I". For example, IEnumerable, IDisposable etc. It is a compiler error to add access specifiers like public or protected to the interface members. Interface members are supposed to be accessible to all the classes implementing the interface, obviously specifying the access specifier doesn't make sense.
Then, I created a class and implemented the interface.
Immediately, I got an error saying I didn’t implement the interface member of ISampleInterface.
Even after I implemented the method (without setting it public), the error was still there but with extra details in the error message.
I just had to make the method public and the error is gone.
This is an important thing to note. Until we specify the method as public, it is not accessible with my interface type object holding a reference to the class.
That is, the instance sampleClass created using ISampleInterface sampleClass = new SampleClass(); will not be able to access the MySampleMethod() because it is not public.
Another way of getting rid of the error is, by specifying the name of the interface just before the method name followed by a dot operator.
Both are different in functionality, we will look into that later.
Ok, everything has been simple and straightforward so far. Now let us go to the real topic of this article.
We all write and implement interfaces often, and we even implement multiple interfaces in classes many times.
A complex scenario that we may come across while implementing multiple interfaces is, a method having the same signature in multiple interfaces.
Let us see how we will need this, and how it works.
Implementing multiple interfaces with the same method name
Let us understand this through an example.
I am using error logging as a sample scenario for this. Suppose, we have a CustomLogger class for logging errors and warnings. Since we may be needing to use different types of error logging mechanisms at different times, it is better to have different interfaces for these.
Create a class ILogger.cs and add two interfaces IFileLogger and IDatabaseLogger.
Both have a method called LogError with the same signature.
- void LogError(string error);
So far, everything is fine.
Now, I am implementing these interfaces in my class.
- public class CustomLogger: IFileLogger,IDatabaseLogger
- {
- public void LogError(string error)
- {
- Console.WriteLine(error);
- }
- }
At this point of time, many of you will be thinking whose LogError method is being implemented.
There is a hint in Visual Studio if you look at the references section above the method.
It shows two references, and I haven’t created an instance of the class as well.
If you click on the text ‘2 references’ and expand it, you can see that both IFileLogger and IDatabaseLogger reference it.
Now, let’s create an object of CustomerLogger class and assign its reference to the variables of CustomerLogger, IFileLogger, and IDatabaseLogger.
- CustomLogger customLogger = new CustomLogger();
- IFileLogger fileLogger = new CustomLogger();
- IDatabaseLogger databaseLogger = new CustomLogger();
-
- customLogger.LogError();
- fileLogger.LogError();
- databaseLogger.LogError();
You will get the same output, as the same method is tied to all the objects.
Implementing a method to use only by a specific interfaceEarlier we have seen that we can specify a method with the name of the interface without making it public. In the context of our current example, I want the application to be able to write a log either to a file, event viewer or to a database.
This selection of medium may be decided based on a configuration in the file or through a UI screen by a user. So, in such cases, I should be able to write a log to the selected medium. For this, I am going to implement the Write methods of IFileLogger and IDatabaseLogger interfaces.
We have already created objects for class and the two interfaces.
Take note of the highlighted references section.
LogError() has only one reference from
- customLogger.LogError();.
IFileLogger.LogError() has references from,
- interface IFileLogger and
- fileLogger.LogError();
IDatabaseLogger.LogError() has references from,
- interface IDatabaseLogger and
- databaseLogger.LogError();
Ok, let’s run the code and check the output.
Yes, each instance of CustomLogger class on each object is tied only to its version of the LogError method.
An interesting thing you can try is, make the IFileLogger.LogError()public and you will get the following error.
The lessons from our tests are,
- If only one implementation of the method is given, it is accessible to the class and all the interfaces which have the same method defined.
- To give the specific implementation of each interface we need to specify the name of the interface followed by dot operator. For example IFileLogger.LogError().
Please use the attached source code to do further experiments.
Thank you for reading!