BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

C# Programming
.NET 1.1+

C# Interfaces

The twenty-first part of the C# Object-Oriented Programming tutorial completes the investigation of polymorphism in the C# programming language. This instalment describes the use of interfaces to determine required members in classes that implement them.

Testing the Classes

We can now test the cat and fish classes using the Main method of the program. For this simple test, we will create both a cat and a fish object before making the cat try to attack the fish. Modify the Main method as follows and execute the program to perform the test.

static void Main(string[] args)
{
    Cat tabby = new Cat();
    tabby.AttackSpeed = 10;

    Fish bubbles = new Fish();
    bubbles.FleeSpeed = 12;

    tabby.Purr();
    tabby.Attack(bubbles);
}

/* OUTPUT

Cat purred
Prey escaped

*/

Using polymorphism techniques, it is possible to declare a variable using an interface as its type. Although an interface cannot be instantiated, such a variable can be assigned an object of any type that implements the interface. This means that the previous example can be rewritten as shown below. However, as the interface for predators does not contain the "Purr" method, this becomes unavailable and must be removed.

static void Main(string[] args)
{
    IPredator tabby = new Cat();
    tabby.AttackSpeed = 10;

    IPrey bubbles = new Fish();
    bubbles.FleeSpeed = 12;

    tabby.Attack(bubbles);
}

Implementing Multiple Interfaces

Earlier in the article I mentioned that a single class can implement more than one interface. This provides even more flexibility and opportunities for polymorphism, as instantiated objects of such a class can behave in many different ways according to the interface in use at any given time.

To declare a class that implements more than one interface, the list of interfaces is appended to the class declaration. The list is comma-separated and is preceded by a colon (:). If the class is also inheriting from a base class, the interface list must appear after the name of the parent class.

In our example, we have declared a class for fish and implemented the IPrey interface. Of course, fish can be predators too so we can sensibly implement the IPredator interface for this class. To add the interface to the Fish class, modify the declaration for the class as follows:

class Fish : IPrey, IPredator

Now that the Fish class is to implement the IPredator interface, the relevant members must be declared before the class will compile. Add the following property and method to the class:

private int _attackSpeed;

public int AttackSpeed
{
    get { return _attackSpeed; }
    set { _attackSpeed = value; }
}

public void Attack(IPrey prey)
{
    if (_attackSpeed > prey.FleeSpeed)
        Console.WriteLine("Caught prey");
    else
        Console.WriteLine("Prey escaped");
}

We can now modify the Main method of the program to test the use of a fish as both predator and prey. Note the use of polymorphism of the Fish class as it acts as both an IPredator object for the attacker and an IPrey object for the intended prey parameter.

static void Main(string[] args)
{
    IPredator shark = new Fish();
    shark.AttackSpeed = 30;

    IPrey ray = new Fish();
    ray.FleeSpeed = 15;

    shark.Attack(ray);
}

/* OUTPUT

Caught prey

*/

Explicit Interface Implementation

In the examples above, all interface members have been implemented in the Cat and Fish classes using implicit implementation. This method requires that public members are created and appear as part of the public interface of the class. Another manner in which interfaces can be realised is known as explicit implementation.

When using explicit implementation, the fully qualified name of each interface member is used in the class definition. This means that both the member name and the interface name are included in each declaration, separated by a full stop, or period. We can demonstrate explicit implementation by modifying the Cat class's IPredator method and property as follows. Note the use of the IPredator prefixes for the two interface members and that the "public" keyword has been removed.

int IPredator.AttackSpeed
{
    get { return _attackSpeed; }
    set { _attackSpeed = value; }
}

void IPredator.Attack(IPrey prey)
{
    if (_attackSpeed > prey.FleeSpeed)
        Console.WriteLine("Caught prey");
    else
        Console.WriteLine("Prey escaped");
}

One of the key benefits of explicit implementation is seen when a class implements multiple interfaces. If several interfaces included a matching member declaration, this would lead to ambiguity in a class using implicit implementation. As the explicit syntax names the interface being inherited, the ambiguity is removed.

Explicitly implemented members become partially private. In the Cat example, if a Cat object is created the interface members are not available. Only if a Cat object is seen within an IPredator variable does the property and method become available. The following code is therefore invalid:

Cat c = new Cat();
c.AttackSpeed = 30;

Finally, as the members are private within the Cat class, they are not available for inheritance to subclasses. This means that is not valid to mark such an item as either virtual or abstract.

15 April 2008