C# Interface

  • C# interface can only contain the signatures of methods, properties, events or indexers without any implementations.
  • The classes or structs which implement an interface must take responsibility to realize the functions of each members declared in the interface.
  • Interface members can't be static or includes any access modifiers but they are all implicitly public.
  • A derived class can only inherit from one base class but can implement multiple interfaces with one time implementation for the same signature.
  • An interface is allowed to implement other interfaces but is not allowed to be instantiated directly.
  • The virtual keyword can be added to implement interface members and abstract can be added as well in an abstract class.

C# interface syntax with only methods looks as below.

interface <interface Name>
{
	<return type> <member name>([Parameter List]);
	...
}

Example 01-71-01

The example 01-70-02 in C# Polymorphism is changed as follows.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
using System;
using System.Collections.Generic;

interface Shape
{
    void area();
}

class Rectangle : Shape
{
    private double length;
    private double width;

    public Rectangle(double length, double width)
    {
        this.length = length;
        this.width = width;
    }

    public void area()
    {
        Console.WriteLine("Rectangel Area: {0}", length * width);
    }
}

class Triangle : Shape
{
    private double baseline;
    private double height;

    public Triangle(double baseline, double height)
    {
        this.baseline = baseline;
        this.height = height;
    }

    public void area()
    {
        Console.WriteLine("Triangel Area: {0}", baseline * height / 2.0);
    }
}

class Circle : Shape
{
    const double PI = 3.14;
    private double radius;

    public Circle(double radius)
    {
        this.radius = radius;
    }

    public void area()
    {
        Console.WriteLine("Circle Area: {0}", radius * radius * PI);
    }
}

public class TestShape
{
    static void Main()
    {
        List shapes = new List();
        Shape shape1 = new Rectangle(10, 10);
        shapes.Add(shape1);
        shapes.Add(new Circle(10));
        shapes.Add(new Triangle(10, 10));
        shapes.Add(new Circle(20));

        foreach (Shape s in shapes)
        {
            s.area();
        }

        Console.Read();
    }
}

Output

Rectangel Area: 100
Circle Area: 314
Triangel Area: 50
Circle Area: 1256

Explanation

  • Line 4-7: The abstract class Shape was changed to interface Shape.
  • Line 20,37,53: The override keyword was removed because the area() was not a virtual or abstract method any more.
  • We got the same result as before.

Example 01-71-02

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
using System;

interface A
{
    void method1();
}

interface B : A
{
    void method2();
}

public abstract class C : B
{
    public abstract void method1();
    public virtual void method2()
    {
        Console.WriteLine("Method2 in class C");
    }
}

public class D : C
{
    public override void method1()
    {
        Console.WriteLine("Method1 in class D");
    }

    public override void method2()
    {
        Console.WriteLine("Method2 in class D");
    }
}

public class TestInterface
{
    static void Main()
    {
        B b = new D();
        b.method1();
        b.method2();

        Console.Read();
    }
}

Output

Method1 in class D
Method2 in class D

Explanation

  • Line 3-6: Define an interface A with a signature of method1.
  • Line 8-11: Define an interface B implements A and add the second method.
  • Line 13-20: Define an abstract class C that implements interface B.
  • Line 15: Use abstract method1() to realize the interface member, public is needed.
  • Line 16: Use public virtual method2() to realize the interface member.
  • Line 22-33: Class D inherits from C and the two override methods.
  • Line 39: Create an object of D and assign it to b which is an instance of interface B.
  • A class can only inherit from one class including abstract class but can implement multiple interfaces.
  • An interface can only declare the signatures of methods, properties, events or indexers but an abstract class does not has the limitation.
  • Public is automatically the access level of all the interface members but cannot be shown up explicitly; An abstract class has no this limitation.
  • No implementation of any members can be found in an interface but an abstract class is allowed to include implementation of its members.
  • An interface is recommended to be used among unrelated classes but an abstract class is always used as the base class of a class inheritance hierarchy.

Example 01-71-03

This is a good example to implement multiple interfaces.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
using System;

interface IName
{
    string whoAmI();
}

interface IJog
{
    void jog();
}

interface IRepair
{
    void repair();
}

public class Person: IName, IJog
{
    public string whoAmI()
    {
        return "A person";
    }

    public void jog()
    {
        Console.WriteLine(" is jogging.");
    }
}

public class Car : IName, IRepair
{
    public string whoAmI()
    {
        return "A car";
    }

    public void repair()
    {
        Console.WriteLine(" is being repaired.");
    }
}

public class TestInterface2
{
    static void Main()
    {
        Person p = new Person();
        Console.Write(p.whoAmI());
        p.jog();

        Car c = new Car();
        Console.Write(c.whoAmI());
        c.repair();

        Console.Read();
    }
}

Output

A person is jogging.
A car is being repaired.

Explanation

  • Line 3-16: Define 3 interfaces.
  • Line 18-29: Define a class Person implementing interface IName and IJog. Unlike inheritance, a class is allowed to implements more than one interface.
  • Line 31-42: Define a class Car implementing interface IName and IRepair. All the methods in the interfaces are implemented completely.
  • Line 46-57: Tested and the result is printed as expected.

What will be happened if 2 interfaces defines a method with same signature and a class unfortunately has to implement both interfaces? The following example will demonstrate the solution and the implementation is called Explicit Interface Implementation in C#.

Example 01-71-04

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
using System;

interface IPerson
{
    void drive();
}

interface ICar
{
    void drive();
}

public class PersonWithCar : IPerson, ICar
{
    public void drive()
    {
        Console.WriteLine("Drive!");
    }
}

class Test
{
    static void Main()
    {
        PersonWithCar p = new PersonWithCar();
        p.drive();

        Console.Read();
    }
}

Output

Drive!

Explanation

  • Line 3-19: Declare one method drive() in 2 interfaces with the same signature.
  • Line 15-18: Implements the drive() defined in both interfaces.
  • Line 25-26: Create an instance of the class and call the method.

In the above example, drive() in the class PersonWithCar realize the function in both interfaces. What will be happened if the functions are different? The answer is to implement the function separately by adding the interface name as prefix with dot operator and the method can only be called through the corresponding interface variable. In this case, the access modifier is not allowed. See the example below.

Example 01-71-05

This example is changed from the example 01-71-04

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
using System;

interface IPerson
{
    void drive();
}

interface ICar
{
    void drive();
}

public class PersonWithCar : IPerson, ICar
{
    void IPerson.drive()
    {
        Console.WriteLine("The person is driving.");
    }

    void ICar.drive()
    {
        Console.WriteLine("The car is being driven.");
    }
}

class Test
{
    static void Main()
    {
        PersonWithCar p = new PersonWithCar();
        IPerson ip = (IPerson)p;
        ICar ic = (ICar)p;
        ip.drive();
        ic.drive();

        Console.Read();
    }
}

Output

The person is driving.
The car is being driven.

Explanation

  • Line 15-23: Implementing drive() separately with the interface name added. We call this method name as a fully qualified name. The access modifier in front of the method return type is not allowed.
  • Line 30-34: Create an object of the class and assign it to the interface variables separately then called the method. As you see the result, the method was executed separately. Here p.drive() is not legal and the method must be called through the interface.