C# Tutorial - Interface

Interface

An interface contains definitions for a group of related functionalities that a class or a struct can implement.

By using interfaces, you can, for example, include behavior from multiple sources in a class. That capability is important in C# because the language doesn't support multiple inheritance of classes. In addition, you must use an interface if you want to simulate inheritance for structs, because they can't actually inherit from another struct or class.

Interfaces can contain methods, properties, events, indexers, or any combination of those four member types.

To implement an interface member, the corresponding member of the implementing class must be public, non-static, and have the same name and signature as the interface member.

When a class or struct implements an interface, the class or struct must provide an implementation for all of the members that the interface defines.

Interfaces properties

  • An interface is like an abstract base class. Any class or struct that implements the interface must implement all its members.
  • An interface can't be instantiated directly. Its members are implemented by any class or struct that implements the interface.
  • Interfaces can contain events, indexers, methods, and properties.
  • Interfaces contain no implementation of methods.
  • A class or struct can implement multiple interfaces. A class can inherit a base class and also implement one or more interfaces.

Defining an Interface

Defining an interface is similar to defining a class — you use the interface keyword followed by an identifier (the name of the interface) and then specify the interface body. For example:

 interface IPerson
    {
        string Name { get; set; }
        DateTime DateofBirth { get; set; }
        ushort Age();
    }

Implementing an Interface

Once an interface is defined, you can create a new class to implement it. The class that implements that particular interface must provide all the implementation for the members defined in that interface.

For example, here ’ s an Employee class that implements the IPerson interface:

public class Employee : IPerson
    {
        public string Name { get; set; }
        public DateTime DateofBirth { get; set; }
        public ushort Age()
        {
            return (ushort)(DateTime.Now.Year - this.DateofBirth.Year);
        }
    }

Implementing Multiple Interfaces

A class can implement any number of interfaces. This makes sense because different interfaces can define different sets of behaviors (that is, members) and a class may exhibit all these different behaviors at the same time.

interface IAddress
    {
        string Street { get; set; }
        uint Zip { get; set; }
        string State();
    }

The full implementation of the Employee class looks like this:

public class Employee : IPerson, IAddress
    {
        //---IPerson---
        public string Name { get; set; }
        public DateTime DateofBirth { get; set; }
        public ushort Age()
        {
            return (ushort)(DateTime.Now.Year - this.DateofBirth.Year);
        }
        //---IAddress---
        public string Street { get; set; }
        public uint Zip { get; set; }
        public string State()
        {
            //---some implementation here---
            return "Rajasthan";
        }
    }

Extending Interfaces

You can extend interfaces if you need to add new members to an existing interface.

interface IManager : IPerson
    {
        string Dept { get; set; }
    }

To use the IManager interface, you define a Manager class that implements the IManager interface, like this:

public class Manager : IManager
    {
        //---IPerson---
        public string Name { get; set; }
        public DateTime DateofBirth { get; set; }
        public ushort Age()
        {
            return (ushort)(DateTime.Now.Year - this.DateofBirth.Year);
        }
        //---IManager---
        public string Dept { get; set; }
    }

You can also extend multiple interfaces at the same time. The following example shows the IManager interface extending both the IPerson and the IAddress interfaces:

 public class Manager : IManager
    {
        //---IPerson---
        public string Name { get; set; }
        public DateTime DateofBirth { get; set; }
        public ushort Age()
        {
            return (ushort)(DateTime.Now.Year - this.DateofBirth.Year);
        }
        //---IManager---
        public string Dept { get; set; }
        //---IAddress---
        public string Street { get; set; }
        public uint Zip { get; set; }
        public string State()
        {
            //---some implementation here---
            return "Rajasthan";
        }
    }

The is and as Operators

Performing a direct cast is safe only if you are absolutely sure that the object you are casting implements the particular interface you are trying to assign to. Consider the following case where you have an instance of the Employee class:

Employee e1 = new Employee();

The Employee class implements the IPerson and IAddress interfaces. And so if you try to cast it to an instance of the IManager interface, you will get a runtime error:

//---Error: Invalid cast exception---
IManager m = (IManager) e1;

To ensure that the casting is done safely, use the is operator. The is operator checks whether an object is compatitble with a given type. It enables you to rewrite the casting as:

if (m1 is IPerson)
            {
                IPerson p = (IPerson)m1;
                Console.WriteLine(p.Age());
                Console.WriteLine(p.Name);
                Console.WriteLine(p.DateofBirth);
            }
            if (m1 is IAddress)
            {
                IAddress a = (IAddress)m1;
                Console.WriteLine(a.Street);
                Console.WriteLine(a.Zip);
                Console.WriteLine(a.State());
            }
            if (e1 is IManager)
            {
                IManager m = (IManager)e1;
            }

Using the is operator means that the compiler checks the type twice — once in the is statement and again when performing the actual casting. So this is actually not very efficient. A better way would be to use the as operator.The as operator performs conversions between compatible types. Here ’ s the preceding casting rewritten using the as operator:

IPerson p = m1 as IPerson;
if (p != null)
{
Console.WriteLine(p.Age());
Console.WriteLine(p.Name);
Console.WriteLine(p.DateofBirth);
}
IAddress a = m1 as IAddress;
if (a != null)
{
Console.WriteLine(a.Street);
Console.WriteLine(a.Zip);
Console.WriteLine(a.State());
}
Employee e1 = new Employee();
//---m is null after this statement---
IManager m = e1 as IManager;
if (m != null)
{
//...
}

Overriding Interface Implementations

When implementing an interface, you can mark any of the methods from the interface as virtual . For example, you can make the Age() method of the Employee class virtual so that any other classes that inherit from the Employee class can override its implementation:

 public interface IPerson
    {
        string Name { get; set; }
        DateTime DateofBirth { get; set; }
        ushort Age();
    }
    public class Employee : IPerson
    {
        public string Name { get; set; }
        public DateTime DateofBirth { get; set; }
        public virtual ushort Age()
        {
            return (ushort)(DateTime.Now.Year - this.DateofBirth.Year);
        }
    }
  public class Director : Employee
    {
        public override ushort Age()
        {
            return base.Age() + 1;
        }
    }

Interface Example in C#

using System;

namespace InterfaceApp
{
    public interface IPerson
    {
        string Name { get; set; }
        DateTime DateofBirth { get; set; }
        ushort Age();
    }
    
    
    interface IAddress
    {
        string Street { get; set; }
        uint Zip { get; set; }
        string State();
    }
    public class Employee : IPerson, IAddress
    {
        //---IPerson---
        public string Name { get; set; }
        public DateTime DateofBirth { get; set; }
        public virtual ushort Age()
        {
            return (ushort)(DateTime.Now.Year - this.DateofBirth.Year);
        }
        //---IAddress---
        public string Street { get; set; }
        public uint Zip { get; set; }
        public string State()
        {
            //---some implementation here---
            return "Rajasthan";
        }
    }
    interface IManager : IPerson, IAddress
    {
        string Dept { get; set; }
    }
    public class Manager : IManager
    {
        //---IPerson---
        public string Name { get; set; }
        public DateTime DateofBirth { get; set; }
        public ushort Age()
        {
            return (ushort)(DateTime.Now.Year - this.DateofBirth.Year);
        }
        //---IManager---
        public string Dept { get; set; }
        //---IAddress---
        public string Street { get; set; }
        public uint Zip { get; set; }
        public string State()
        {
            //---some implementation here---
            return "Rajasthan";
        }
    }
    public class Director : Employee
    {
        public override ushort Age()
        {
            return (ushort)( base.Age() + 1);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Manager m1 = new Manager()
            {
                Name ="Mukesh Dhakar",
                DateofBirth = new DateTime(1985, 03,05),
                Dept = "IT",
                Street ="Durga Nursary Road",
                Zip = 313001
            };
            Console.WriteLine(m1.Age());
            Console.WriteLine(m1.State());
            Employee e1 = new Employee();
            if (m1 is IPerson)
            {
                IPerson p = (IPerson)m1;
                Console.WriteLine(p.Age());
                Console.WriteLine(p.Name);
                Console.WriteLine(p.DateofBirth);
            }
            if (m1 is IAddress)
            {
                IAddress a = (IAddress)m1;
                Console.WriteLine(a.Street);
                Console.WriteLine(a.Zip);
                Console.WriteLine(a.State());
            }
            if (e1 is IManager)
            {
                IManager m = (IManager)e1;
            }


            Director d = new Director();
            d.DateofBirth = new DateTime(1970, 7, 28);
            Console.WriteLine(d.Age());
        }
    }
}