Interfaces in C#

( 1 user )

In the previous chapter, we saw how Abstract classes allow us to provide the method signature and hence the child classes were able to override and provide their own method body and still the base class references were perfectly working with child class objects. Along with this, the abstract classes can have methods with complete definitions as well. So, it's a mix of both blank methods and defined methods.

An Interface does not have any method definition. It just declares methods. The classes which inherit the interface must implement all of its methods. That is the reason an interface is also sometimes called as a Contract since there is always a guarantee that the implementer class has implemented all the methods of the Interface which is not in the case of an Abstract class. The interface is said to add common behavior to the classes.

So, why exactly it is called an Interface? Taking an example of USB, everyone knows USB devices. No matter what the device is, it must have the same Interface that plugs your USB device to a USB socket. Here, the USB plug and socket are the contracts and the USB devices are the classes adhering to those contracts. In this way, the devices (or classes) will guarantee that it can be plugged in any USB socket via an Interface. Hence, it is called an Interface.

The general syntax of creating an Interface is:


interface interface-name
{
	// declarations
}
		

The general syntax to use an Interface is:


class class-name : interface-name
{
	// implementations
}
		

Implementing an Interface

Let's understand this more with an example by creating an Interface (or contract in object-oriented programming terms). We are going to create an interface called "IMobile". By convention, interface names begin with the capital letter "I".


interface IMobile
{

}
		

Here, "IMobile" is a contract that says that every mobile that is being built by a company must strictly adhere to it. The question is what would be the rules to adhere. The rules would be the method signature. So the IMobile will tell that every mobile must have the implementation of these methods. So, let's declare some contract methods in the "IMobile" interface.


interface IMobile 
{
	void Start();
	void SetDateTime(DateTime dateTime);
	void SetRingingMode(string ringingMode);
	void ConnectToNetwork();
	void ShutDown();
}
		

The above Interface says that the contract is to strictly implement all of these five methods in each mobile using this Interface. Let's say the company is manufacturing two models "M25" and "N32". So now let's define a mobile adhering to this "IMobile" interface.

Run this code


class M25 : IMobile
{
	public void Start()
	{
		Console.WriteLine("Starting M25");
	}
	
	public void SetDateTime(DateTime dateTime)
	{
		Console.WriteLine($"Date and Time are set to {dateTime.ToShortDateString()}, {dateTime.ToShortTimeString()}");
	}
	
	public void SetRingingMode(string ringingMode)
	{
		if(ringingMode == "vibration")
		{
			Console.WriteLine("Sorry : vibration mode type is not supported");
			return;
		}
		Console.WriteLine($"Setting ringingMode to {ringingMode}");
	}
	
	public void ConnectToNetwork()
	{
		Console.WriteLine("Connecting to default network");
	}
	
	public void ShutDown()
	{
		Console.WriteLine("Shutting down M25...");
	}
}


class N32 : IMobile
{
	public void Start()
	{
		Console.WriteLine("Starting N32");
	}
	
	public void SetDateTime(DateTime dateTime)
	{
		Console.WriteLine($"Date and Time are set to {dateTime.ToShortDateString()}, {dateTime.ToShortTimeString()}");
	}
	
	public void SetRingingMode(string ringingMode)
	{
		Console.WriteLine($"Setting ringingMode to {ringingMode}");
	}
	
	public void ConnectToNetwork()
	{
		Console.WriteLine("Connecting to default network");
	}
	
	public void ShutDown()
	{
		Console.WriteLine("Shutting down N32...");
	}
}
		

So the company has now two manufacturing units one for "M25" and another for "N32" and now it can start manufacturing these two mobiles. So, let's create two concrete mobiles out of these classes.


var m25 = new M25();
var n32 = new N32();
		

As you can see we have created two objects of each type of mobile. Since we know the contract (methods inside the Interface), we can call those methods and it will work absolutely fine.

		
m25.Start();
n32.Start();
		

Using Interface references

In the above program, we have used class' references to create objects. Similar to abstract classes, one of the properties of an interface is that we can create objects of implementer classes with Interface references. To understand this, let's first modify our main program.


IMobile m25 = new M25();

IMobile n32 = new N32();
		

Now since the Contract or Interface has declared the method Start(), calling this method on Interface reference will still work.


m25.Start();
n32.Start();
		

You might be wondering nothing fancy happened here, we just changed the actual class' reference to Interface reference. Did you remember the last chapter where we could pass the child class' instance to a method with a parameter of parent class type? Similarly, we can do here.

So let's suppose the company wants to test all the features of each of the mobile before dispatching them into the market. Also, the company does not want to create separate testing units for each type of mobile to cater to cost savings. For this purpose, we need to create a method in our main program and use interface instead of actual mobile types.

Run this code


void TestMobileDevice(IMobile mobileDevice)
{
	mobileDevice.Start();
	mobileDevice.SetDateTime(DateTime.Now());
	mobileDevice.SetRingingMode("silent");
	mobileDevice.SetRingingMode("vibration");
	mobileDevice.ConnectToNetwork();
	mobileDevice.ShutDown();
}
		

Now, we can pass the objects of both type mobiles into this method and it will work perfectly.


TestMobileDevice(m25);
TestMobileDevice(n32);
		

Abstract class v/s Interface

Although, Interfaces and Abstract classes seem similar and there are many theories around it like when to use abstract class and when to use Interface. Over a few years, I intuitively tried to figure out what should we call those use cases which clearly differentiate between these two. I somehow ended up calling it an absolute contract and a partial contract.

An abstract class can have both well-defined methods and abstract methods. In this case, the derived class must implement the abstract method(s) but need not necessarily override the well-defined methods of the abstract class. Hence it is a partial contract where some rules are optional to follow. However, in the case of Interface, all rules must be followed hence its an absolute contract.

Note : Please note that if all methods of an abstract class are abstract then it should be converted into an Interface.

In the real world, you can visualize an abstract class as a Professor who can do many things on his own but is also responsible for set guidelines and delegate several tasks to the teachers. The teachers must do the mandatory tasks as per the guidelines because the professor cannot do that. However, there are some other tasks that either the teacher can do or can ask the Professor to do on its behalf. That's why its a partial contract.

On the other hand, you can visualize the Interface as the rules made by the college itself. A teacher has to follow all those rules. The teacher can not fall back to any other teacher or professor to follow any of the rules on its behalf. That's why its an absolute contract.

Multiple inheritance with Interfaces

A class can not be derived from more than one base class. However, it is possible using Interface. We can inherit more than one Interface in a class. All the methods of all inherited interfaces must be implemented by the derived class.

Continuing with our previous example, we want to introduce 4G internet into the mobiles. So, we are going to create an interface I4GNetwork which will have one method CheckInternetConnection();.


interface I4GNetwork
{
	void CheckInternetConnection();
}
		

Since we only want our N32 mobile to be 4G capable, we are going to implement this interface in our N32 mobile.


class N32 : IMobile, I4GNetwork
{
	public void Start()
	{
		Console.WriteLine("Starting N32");
	}
	
	public void SetDateTime(DateTime dateTime)
	{
		Console.WriteLine($"Date and Time are set to {dateTime.ToShortDateString()}, {dateTime.ToShortTimeString()}");
	}
	
	public void SetRingingMode(string ringingMode)
	{
		Console.WriteLine($"Setting ringingMode to {ringingMode}");
	}
	
	public void ConnectToNetwork()
	{
		Console.WriteLine("Connecting to default network");
	}

	public void CheckInternetConnection()
	{
		Console.WriteLine("Internet connectivity is OK.");
	}
	
	public void ShutDown()
	{
		Console.WriteLine("Shutting down N32...");
	}
}
		

As you can see in the above example how we were able to derive from multiple interfaces (IMobile and I4GNetwork) and implement the same in our N32 class.

Run this code


class Program
{
	static void Main(string[] args)
	{
		Console.WriteLine("Multiple Inheritance with Interfaces");
		Console.WriteLine();
		
		var n32 = new N32();
		
		n32.Start();
		n32.SetDateTime(DateTime.Now);
		n32.SetRingingMode("silent");
		n32.SetRingingMode("vibration");
		n32.ConnectToNetwork();
		n32.CheckInternetConnection();
		n32.ShutDown();
		
		Console.WriteLine();
		
		Console.Write("Press any key to continue...");
		Console.ReadKey(true);
	}
}
		

Interface deriving other Interface(s)

An interface can also inherit from one or more interfaces. However, it is the responsibility of the implementing class to implement all the methods of the Interface and of it's all ancestor interfaces.

Before understanding this with an example, in the previous examples, we have implemented two interfaces IMobile, I4GNetwork. As a part of object-oriented principles, these two interfaces must be self-independent. As we can see that the interface I4GNetwork cannot be implemented alone without IMobile because it does not make any sense to have a 4G network without a mobile interface or any other device interface per se.

So, in this case, we must introduce another interface say I4GMobile which inherits from IMobile interface. Then our 4G mobile class is going to implement this interface. So, let's modify our previous code.


interface I4GMobile : IMobile
{
	void CheckInternetConnection();
}
		

Here, our new I4GMobile interface is inheriting from our original IMobile interface. Now, our class N32 needs just one modification i.e. just inheriting from this new I4GMobile interface. Also, it needs to implement all method definitions of I4GMobile and IMobile as well which it was already doing.


class N32 : I4GMobile
{
	public void Start()
	{
		Console.WriteLine("Starting N32");
	}
	
	public void SetDateTime(DateTime dateTime)
	{
		Console.WriteLine($"Date and Time are set to {dateTime.ToShortDateString()}, {dateTime.ToShortTimeString()}");
	}
	
	public void SetRingingMode(string ringingMode)
	{
		Console.WriteLine($"Setting ringingMode to {ringingMode}");
	}
	
	public void ConnectToNetwork()
	{
		Console.WriteLine("Connecting to default network");
	}

	public void CheckInternetConnection()
	{
		Console.WriteLine("Internet connectivity is OK.");
	}
	
	public void ShutDown()
	{
		Console.WriteLine("Shutting down N32...");
	}
}
		

Now we can write our main program as follows.

Run this code


class Program
{
	static void Main(string[] args)
	{
		Console.WriteLine("Interface deriving interface");
		Console.WriteLine();
		
		I4GMobile n32 = new N32();
		
		n32.Start();
		n32.SetDateTime(DateTime.Now);
		n32.SetRingingMode("silent");
		n32.SetRingingMode("vibration");
		n32.ConnectToNetwork();
		n32.CheckInternetConnection();
		n32.ShutDown();
		
		Console.WriteLine();
		
		Console.Write("Press any key to continue...");
		Console.ReadKey(true);
	}	
}
		

Explicit Interface implementation

Suppose a class is inheriting from multiple interfaces and some of those interfaces have one common method say foo(). Now if we are going to implement all those interfaces, there will be a conflict.

Let's say we are going to design a text reader that can read the text in two voices say human female and robot. We first need to define the two interfaces that will have a method called Speak().


interface IHumanFemaleReader
{
	Speak();
}

interface IRobotReader
{
	Speak();
}
		

Now, we will define the application class called TextReader which can say in both human female voice and robot voice which reading.


class TextReader : IHumanFemaleReader, IRobotReader
{
	Speak()
	{
		Console.WriteLine("Speaking");
	}
}
		

Can you see a conflict in the above code? We have implemented the method Speak() but we don't know if this method is referring to IHumanFemaleReader or IRobotReader.

What do you think the compiler will do in this case? The answer is - The compiler won't throw any error. However, any interface reference will call this one method only and we can never have two different voices as expected.

To cater to this situation, C# lets us provide an explicit implementation where we can specify the interface name to differentiate methods with same name So, let's modify our class to provide explicit implementations for Speak() method.


class TextReader : IHumanFemaleReader, IRobotReader
{
	public IHumanFemaleReader.Speak()
	{
		Console.WriteLine("Human Female Speaking");
	}
	
	public IRobotReader.Speak()
	{
		Console.WriteLine("Robot Speaking");
	}
}
		

In the above example, for each of the interface where we had conflicted method name, we have provided explicit method definitions. Now, let's write our main program to see this in action.

Run this code


class Program
{
	static void Main(string[] args)
	{
		Console.WriteLine("Explicit Interface Implementation");
		Console.WriteLine();
		
		IHumanFemaleReader humanFemaleReader = new TextReader();
		IRobotReader robotReader = new TextReader(); 
		
		humanFemaleReader.Speak();
		robotReader.Speak();
		
		Console.WriteLine();
		
		Console.Write("Press any key to continue...");
		Console.ReadKey(true);
	}
}
		

To Do

* Note : These actions will be locked once done and hence can not be reverted.

1. Track your progress [Earn 200 points]

2. Provide your ratings to this chapter [Earn 100 points]

0
Note : At the end of this chapter, there is a ToDo section where you have to mark this chapter as completed to record your progress.