MorkaLork Development

Interesting stuff I've picked up over the years...

Interface

2009-04-16 18:04:30 | 231 views | interface inherit inheritance implementation abstract IPerson properties indexers

The basics



In C# you might some times want to have a general rule for several classes. You don’t want them to share the exact same code, but the same elements. An interface sets up rules for a inheriting class by telling it what it has to implement as a minimum in order to avoid compilation errors.
An example:


interface IPerson
{
string Name{get; set;}
int Age{get;set;}

int YearsToRetirement();
}


That’s it, that is what an interface looks like. There is no implementation in an interface, as can be seen in the above example. The only value of the interface is to guarantee that the inheriting classes all have these properties and methods.
There are several reasons why it’s good to to use an interface. One of them is that it helps a user to understand the class. If a class inherits the interface IDispose then the user of that class knows that it has the Dispose() method.
Another reason is that an Interface can be used as a type to create general variables or method parameters. More about this soon.


Rules for interfaces



There are several rules for an interface that you have to consider. Some are optional, some are not.

An interface should be named in the following fashion: Start with a capitol i(I) and follow by a name starting with a capital letter.
Examples: IPerson, IDisposable, IEnumerable

An interface can only contain the following members:


A class can inherit as many interfaces as it wants(whereas it can only inherit one other class)

All members of a class are automatically public(as is the interface).

A class that inherits an interface automatically inherits the member signatures and must implement them.

A class can inherit an interface multiple times(by inheriting other classes or interfaces that inherit that interface). If so, implementation of the interface members only has to occur once. If a method has already been implemented it cannot be implemented again, however it can be overridden if the original implementation was declared virtual.

An interface can be inherited by another interface.

An interface cannot be instantiated.


Next page: An example on how to use interfaces in more detail.
[breakpoint]

Example



Let’s create an interface for a person. The reason we’ll create an interface instead of a root class is that we’ll have a method called YearsToRetirement() that will calculate the years a person has left to retire. We will use this method for various kinds of people such as a student and a professor. The difference between these two characters will be that a student won’t be allowed to studdy if he/she is a senior citizen whereas a professor might be retired but still teaching. If a professor is retired but still studdying we want a check. This will make the two methods similar but not identical, so we just want to announce that there will be a method, but not tell how to implement it.



interface IPerson
{
string Name{get; set;}
int Age{get;set;}

int YearsToRetirement();
}


This interface tells an inheriting class that it must implement two properties, Name and Age and a method, YearsToRetirement(). A class kan have more members, but these are the minimum requirements. A student class could look like this:



public class Student : IPerson
{
private string name;
private int age;
private bool partTimeJob;

public string Name
{
get{return name;}
set{name = value;}
}
public int Age
{
get{return age;}
set{age = value;}
}
public bool PartTimeJob
{
get{return partTimeJob;}
set{partTimeJob = value;}
}

public int YearsToRetirement()
{
return 65 - age;
}
}


As we can see, the class Student inherits IPerson just as it would inherit a class. It then creates properties for Name and Age, but also PartTimeJob which is specific for the student class and tells if a student object has a part time job.
If we hadn’t implemented all the interface members, say the property Name, an error would have been thrown when compiling the project:

'baluba.Student' does not implement interface member 'baluba.IPerson.Name' (CS0535)
(baluba being the namespace)


We can se that our YearsToRetirement method in our Student class calculates the age of retirements minus the current age of the student.
Let’s create a Professor object:



public class Professor : IPerson
{
private string name;
private int age;
private bool hasBeard;

public string Name
{
get{return name;}
set{name = value;}
}
public int Age
{
get{return age;}
set{age = value;}
}
public bool HasBeard
{
get{return hasBeard;}
set{hasBeard = value;}
}

public int YearsToRetirement()
{
int i = 65 - age;

//Make sure years left aren't negativ
if (i < 0) {
i = 0;
}

return i;
}


This class also implements the IPerson interface, but differs from student in the YearsToRetirement method. This is because a professor could be more than 65 years old and still be a professor. In such an event, we don’t want years left to be negative(that would be silly), we just want to return 0 and let the user handle it.
The Professor class also has it’s own specific property, HasBeard, as we can see, and it’s not part of the IPerson interface. Otherwize, Professor implements all the members of IPerson and will compile.
Now, let’s use this:



class Program
{
public static void Main(string[] args)
{
Student s = new Student();

s.Name = "Johan";
s.Age = 25;
s.PartTimeJob = true;

Professor p = new Professor();

p.Name = "Roger";
p.Age = 63;
p.HasBeard = true;
}
}
}


What we can see in this example is that we create two objects, Student s and Professor p. Now we want to print their name, age and time left to retirement. One way would be to create two methods, one that prints student objects and one that prints professor objects. This would however mean that we would have two identical methods that would only differ on the method input parameter. Here is a great opportunity to show the power of interfaces:



public static void PrintPerson(IPerson ip)
{
Console.WriteLine("Name: {0}\nAge: {1}\nYears to retirement: {2}", ip.Name, ip.Age, ip.YearsToRetirement());
}


When we send in an object to the PrintPerson method it has to be an object that inherits the IPerson interface. As mentioned earlier in this article interfaces can’t be instantiated, but they can be used as types. That’s what we do here. An IPerson object has the properties Name and Age and the YearsToRetirement method. It doesn’t matter that they are implemented in different ways, the whole point is that they mean the same thing and the methods return an int telling how long the object has to retirement.
This image illustrates how a student object is used

imagehttp://admin.morkalork.com/uploads/images/interfaces/interfaces1.png

When sending a Student object or a Professor object to the PrintPerson method we accept it as an IPerson object which gives us access to the the members of IPerson. This means that whatever future class that implements IPerson can use the PrintePerson method no matter how it’s designed since it has to implement all it’s members.
Here’s how it’s used in full:



class Program
{
public static void Main(string[] args)
{

Student s = new Student();

s.Name = "Johan";
s.Age = 25;
s.PartTimeJob = true;

Professor p = new Professor();

p.Name = "Roger";
p.Age = 63;
p.HasBeard = true;

PrintPerson(s);
Console.WriteLine("");
PrintPerson(p);


Console.Read();
}

public static void PrintPerson(IPerson ip)
{
Console.WriteLine("Name: {0}\nAge: {1}\nYears to retirement: {2}", ip.Name, ip.Age, ip.YearsToRetirement());
}
}


This would give the following output:

imagehttp://admin.morkalork.com/uploads/images/interfaces/Interfaces2.png

This concludes that the interface forces these two classes to implement all it’s members but does not tell how to implement them.
Now a person could look up the IPerson interface and get an idea of what all classes that implements this interface contains (as minimum). That can clarify a lot and brings us to our next example which will shed more light on the use of interfaces.

Next page: An example on how our program can be reused in the future.
[breakpoint]

Example 2



The reason we want to implement the IPerson interface is because we want to offer our programmers a possibility to plan for the future. If we later on want to create a new person, an employee, we don’t want to have to create a new method just to output the employee, we want to be able to reuse the PrintPerson method. If the Employee class implements the IPerson interfaces it can, however, use the PrintPerson method since it can identify Employee as an IPerson object.



public class Employee : IPerson
{
private string name;
private int age;
private string department;
private int sallary;


public string Name
{
get{return name;}
set{name = value;}
}
public int Age
{
get{return age;}
set{age = value;}
}
public string Department
{
get{return department;}
set{department = value;}
}
public int Sallary
{
get{return sallary;}
set{sallary = value;}
}

public int YearsToRetirement()
{
return 65 - age;
}

}


The Employee class has several more properties but still has the basics of an IPerson interface since it inherits the interface in question. This can now, without problem, be used in the PrintPerson method:



class Program
{
public static void Main(string[] args)
{

Student s = new Student();

s.Name = "Johan";
s.Age = 25;
s.PartTimeJob = true;

Professor p = new Professor();

p.Name = "Roger";
p.Age = 63;
p.HasBeard = true;

Employee e = new Employee();

e.Name = "Marcus";
e.Age = 32;
e.Department = "Economy";
e.Sallary = 26000;

PrintPerson(s);
Console.WriteLine("");
PrintPerson(p);
Console.WriteLine("");
PrintPerson(e);


Console.Read();
}

public static void PrintPerson(IPerson ip)
{
Console.WriteLine("Name: {0}\nAge: {1}\nYears to retirement: {2}", ip.Name, ip.Age, ip.YearsToRetirement());
}
}


This would give the following output:

imagehttp://admin.morkalork.com/uploads/images/interfaces/interfaces3.png

This illustrates how interfaces creates code that can easily be used by future classes as well.

Enjoy!


Article comments

Feel free to comment this article using a facebook profile.

I'm using facebook accounts for identification since even akismet couldn't handle all the spam I receive every day.