C# - Interface
In the human world, a contract between the two or more humans binds them to act as per the contract. In the same way, an interface includes the declarations of related functionalities. The entities that implement the interface must provide the implementation of declared functionalities.
In C#, an interface can be defined using the interface
keyword. An interface can contain declarations of methods, properties, indexers, and events. However, it cannot contain instance fields.
The following interface declares some basic functionalities for the file operations.
interface IFile
{
void ReadFile();
void WriteFile(string text);
}
The above declares an interface named IFile
. (It is recommended to start an interface name with the letter "I" at the beginning of an interface so that it is easy to know that this is an interface and not a class.) The IFile
interface contains two methods, ReadFile()
and WriteFile(string)
.
- An interface can contain declarations of methods, properties, indexers, and events.
- Default interface methods with implementation body are supported from C# 8.0.
- An interface cannot contain constructors and fields.
- Interface members are by default
abstract
andpublic
. - You cannot apply access modifiers to interface members. Although, C# 8.0 onwards, you may use private, protected, internal, public, virtual, abstract, sealed, static, extern, and partial modifiers on certain conditions.
Implementing an Interface
A class or a Struct can implement one or more interfaces using colon :
. On impmenting an interface, you must override all the members of an interface.
class ClassName : InterfaceName
{
}
For example, the following FileInfo
class implements the IFile
interface, so it should override all the members of IFile
.
interface IFile
{
void ReadFile();
void WriteFile(string text);
}
class FileInfo : IFile
{
public void ReadFile()
{
Console.WriteLine("Reading File");
}
public void WriteFile(string text)
{
Console.WriteLine("Writing to file");
}
}
In the above example, the FileInfo
class implements the IFile
interface. It overrides all the members of the IFile
interface with public access modifier. The FileInfo
class can also contain members other than interface members.
public
modifier; otherwise, the compiler will give compile-time errors.You can create an object of the class and assign it to a variable of an interface type, as shown below.
public class Program
{
public static void Main()
{
IFile file1 = new FileInfo();
FileInfo file2 = new FileInfo();
file1.ReadFile();
file1.WriteFile("content");
file2.ReadFile();
file2.WriteFile("content");
}
}
Above, we created objects of the FileInfo
class and assign it to IFile
type variable and FileInfo
type variable. When interface implemented implicitly, you can access IFile
members with the IFile
type variables as well as FileInfo
type variable.
Explicit Implementation
An interface can be implemented explicitly using <InterfaceName>.<MemberName>
. Explicit implementation is useful when class is implementing multiple interfaces; thereby, it is more readable and eliminates the confusion. It is also useful if interfaces have the same method name coincidently.
interface IFile
{
void ReadFile();
void WriteFile(string text);
}
class FileInfo : IFile
{
void IFile.ReadFile()
{
Console.WriteLine("Reading File");
}
void IFile.WriteFile(string text)
{
Console.WriteLine("Writing to file");
}
}
When you implement an interface explicitly, you can access interface members only through the instance of an interface type.
interface IFile
{
void ReadFile();
void WriteFile(string text);
}
class FileInfo : IFile
{
void IFile.ReadFile()
{
Console.WriteLine("Reading File");
}
void IFile.WriteFile(string text)
{
Console.WriteLine("Writing to file");
}
public void Search(string text)
{
Console.WriteLine("Searching in file");
}
}
public class Program
{
public static void Main()
{
IFile file1 = new FileInfo();
FileInfo file2 = new FileInfo();
file1.ReadFile();
file1.WriteFile("content");
//file1.Search("text to be searched")//compile-time error
file2.Search("text to be searched");
//file2.ReadFile(); //compile-time error
//file2.WriteFile("content"); //compile-time error
}
}
In the above example, file1
object can only access members of IFile
, and file2
can only access members of FileInfo
class. This is the limitation of explicit implementation.
Implementing Multiple Interfaces
A class or struct can implement multiple interfaces. It must provide the implementation of all the members of all interfaces.
interface IFile
{
void ReadFile();
}
interface IBinaryFile
{
void OpenBinaryFile();
void ReadFile();
}
class FileInfo : IFile, IBinaryFile
{
void IFile.ReadFile()
{
Console.WriteLine("Reading Text File");
}
void IBinaryFile.OpenBinaryFile()
{
Console.WriteLine("Opening Binary File");
}
void IBinaryFile.ReadFile()
{
Console.WriteLine("Reading Binary File");
}
public void Search(string text)
{
Console.WriteLine("Searching in File");
}
}
public class Program
{
public static void Main()
{
IFile file1 = new FileInfo();
IBinaryFile file2 = new FileInfo();
FileInfo file3 = new FileInfo();
file1.ReadFile();
//file1.OpenBinaryFile(); //compile-time error
//file1.SearchFile("text to be searched"); //compile-time error
file2.OpenBinaryFile();
file2.ReadFile();
//file2.SearchFile("text to be searched"); //compile-time error
file3.Search("text to be searched");
//file3.ReadFile(); //compile-time error
//file3.OpenBinaryFile(); //compile-time error
}
}
Above, the FileInfo
implements two interfaces IFile
and IBinaryFile
explicitly. It is recommended to implement interfaces explicitly when implementing multiple interfaces to avoid confusion and more readability.
Default Interface Methods
Till now, we learned that interface can contain method declarations only. C# 8.0 added support for virtual extension methods in interface with concrete implementations.
The virtual interface methods are also called default interface methods that do not need to be implemented in a class or struct.
interface IFile
{
void ReadFile();
void WriteFile(string text);
void DisplayName()
{
Console.WriteLine("IFile");
}
}
In the above IFile
interface, the DisplayName()
is the default method. The implementation will remain same for all the classes that implements the IFile
interface. Note that a class does not inherit default methods from its interfaces; so, you cannot access it using the class instance.
class FileInfo : IFile
{
public void ReadFile()
{
Console.WriteLine("Reading File");
}
public void WriteFile(string text)
{
Console.WriteLine("Writing to file");
}
}
public class Program
{
public static void Main()
{
IFile file1 = new FileInfo();
file1.ReadFile();
file1.WriteFile("content");
file1.DisplayName();
FileInfo file2 = new FileInfo();
//file2.DisplayName(); //compile-time error
}
}
Learn more on Default interface methods.
Modifiers in Interfaces
C# 8.0 allows private, protected, internal, public, virtual, abstract, sealed, static, extern, and partial modifiers in an interface.
- The default access level for all interface members is
public
. - An interface member whose declaration includes a body is a
virtual
member unless thesealed
orprivate
modifier is used. - A
private
orsealed
function member of an interface must have implementation body. - Interfaces may declare static members which can be accessed by interface name.
Learn more about modifiers in interfaces.