What is an Interface?
An interface is a contract. If you are defining an interface, then you are describing a set of rules. A class can follow the rules specified by the interface. When a class fulfills the contract or rules specified by the interface, we could say that a class implements the interface.
You can define the interface like below.
public interface <interface name>
{
//Specify the Contract
}
A simple interface [ INokiaOld ]
Let us assume there is an interface from the Old cell phone model from Nokia. The interface can be.
public interface INokiaOld
{
void SendSMS();
void HoldCall();
}
The above code specifies a contract for old Nokia mobile phones; that is, all the phone class that implements INokiaOld should implement the function SendSMS and HoldCall. It does not matter how it will be implemented. Say for HoldCall(), some Phones can implement Hold the call for 15 Seconds and Disconnect, or some other phones can implement Hold the call for 60 Seconds and give a beep every five seconds. The contract says, "If a phone adheres to INokiaOld, it should able to send an SMS, and it should provide the facility to hold the call.
Implementing an Interface [ INokiaOld ]
Below is the class which implements the INokiaOld interface.
using System;
// 002: Class that implements the Contract
class MyNokiaOldPhone : INokiaOld
{
// 002_1: A Non Contract Function
public void SomeFunction1()
{
Console.WriteLine("Some Function 1");
}
// 002_2: Contract Function 1
public void SendSMS()
{
Console.WriteLine("SMS Sent");
}
// 002_3: Contract Function 2
public void HoldCall()
{
Console.WriteLine("Call Temporarily on Hold");
}
}
Note that it supports some other functionality like somefunction1(). What is important is as it implements the interface INokiaOld, it is giving the implementation for 1)SendSMS and 2)HoldCall.
From the client's perspective, given the contract name, it is guaranteed that what functionality it can expect from the class object and make use of it. Below is the usage of the INokiaOld.
using System;
class Program
{
static void Main(string[] args)
{
// Usage 001: Use a Simple Interface
MyNokiaOldPhone phone = new MyNokiaOldPhone();
phone.SendSMS();
phone.SomeFunction1();
// Usage 002: Only interface functions can be accessed by iface.
INokiaOld iface = phone;
iface.SendSMS();
}
}
class MyNokiaOldPhone : INokiaOld
{
public void SomeFunction1()
{
Console.WriteLine("Some Function 1");
}
public void SendSMS()
{
Console.WriteLine("SMS Sent");
}
public void HoldCall()
{
Console.WriteLine("Call Temporarily on Hold");
}
}
public interface INokiaOld
{
void SendSMS();
void HoldCall();
}
From the above code, Usage001 has nothing to do with the interface. It just sees the phone as a normal class object. But, when we look at usage002, the following points are revealed.
- The interface type iface is pointing to the MyNokiaOldPhone object.
- iface is guaranteed to have access to the functionality contracted through INokiaOld.
- As iface is INokiaOld type, it cannot have access to somefunction1(). Yeah, somefunction1() is not a contracted one.
Extending an interface [ INokiaNew ]
Below is the syntax for extending an interface from the existing one. It is quite similar to class inheritance. INokiaNew interface is created to support a new function of Sending MMS with an additional to basing feature supported by the old interface. The interface is shown below.
//003: Extended Interface
public interface INokiaNew: INokiaOld
{
void SendMMS_AVI();
}
When a Class implements this new Interface INokiaNew, it should give basic functionality expected by INokiaOld plus Send the MMS in AVI format expected by INokiaNew.
Below is the class.
using System;
class Program
{
static void Main(string[] args)
{
// Usage 003:
MyNokiaNewPhone phone2 = new MyNokiaNewPhone();
INokiaOld iface_basic = phone2;
INokiaNew iface_delux = phone2;
iface_basic.SendSMS(); // You can't send MMS as it is a basic interface
iface_delux.SendSMS(); // You can access basic functionality
iface_delux.SendMMS_AVI(); // You can access extended functionality also
}
}
class MyNokiaNewPhone : INokiaNew
{
public void SomeFunction1()
{
Console.WriteLine("Some Function 1");
}
public void SendSMS()
{
Console.WriteLine("SMS Sent");
}
public void HoldCall()
{
Console.WriteLine("Call Temporarily on Hold");
}
public void SendMMS_AVI()
{
Console.WriteLine("MMS Sent in AVI Format");
}
}
public interface INokiaOld
{
void SendSMS();
void HoldCall();
}
public interface INokiaNew : INokiaOld
{
void SendMMS_AVI();
}
Note that iface_basic can only access the functionality of the basic interface, which is nothing but Sending an SMS and Holding the call. But, through iface_delux, you access all three functionality; that is, two basic (SMS, Call Hold) and one extended (MMS).
Implementing More than One Interface [INokiaNew, ISamSung ]
Let Us Assume that below is the ISamSung interface contract.
using System;
public interface ISamsung
{
void SendMMS_Mpeg();
// Commented the Below Function as per Balaji's reply.
// void PlayMusic();
}
class HybridPhone : INokiaOld, ISamsung
{
public void SendSMS()
{
Console.WriteLine("SMS Sent");
}
public void HoldCall()
{
Console.WriteLine("Call Temporarily on Hold");
}
public void SendMMS_Mpeg()
{
Console.WriteLine("MMS Sent in MPeg format");
}
}
class Program
{
static void Main(string[] args)
{
HybridPhone phone = new HybridPhone();
INokiaOld nokiaInterface = phone;
ISamsung samsungInterface = phone;
nokiaInterface.SendSMS();
nokiaInterface.HoldCall();
samsungInterface.SendMMS_Mpeg();
}
}
public interface INokiaOld
{
void SendSMS();
void HoldCall();
}
The client code now can access the Samsung functionality as well as basic Nokia functionality from the Class object HybridPhone. Below is the code that will demonstrate this.
HybridPhone phone3 = new HybridPhone();
// 004_1: Use Nokia Interface
INokiaOld iface_nokia = phone3;
iface_nokia.SendSMS();
// 004_2: Use Samsung interface
ISamsung iface_samsung = phone3;
Note how the interface functionality is extracted from the same phone object using different interface types. You can not get the Samsung functionality through the INokiaOld interface and the Basic Nokia functionality through the SamSung interface.
Casting the Interface - Is versus As
Look at the below code.
HybridPhone phone3 = new HybridPhone();
INokiaOld iface_nokia = phone3;
// 005_1: Check the Type using is keyword
if (iface_nokia is ISamsung)
{
// 005_2: Cast it to the other interface type
ISamsung iface_samsung1 = (ISamsung)iface_nokia;
iface_samsung1.SendMMS_Mpeg();
}
In the above code, first, we are checking iface_nokia is Samsung type. The first look will get you to give the answer NO. But, note that, here if you read it like "Does the object pointed by the interface type INokiaOld is ISamSung as well". You do say Yes now. Look at how (005_2) casting the object pointed by iface_nokia is done to ISamSung. Once the Casting is done, you can access the functionality of Samsung.
HybridPhone phone3 = new HybridPhone();
INokiaOld iface_nokia = phone3;
// 005_3: Cast and Assign
ISamsung iface_samsung2 = iface_nokia as ISamsung;
iface_samsung2?.SendMMS_Mpeg(); // Using the null conditional operator for safety
If you look at the above code, the 'As' keyword also does the same job. When Object is not ISamSung we will get NULL assigned to iface_samsung2.