Interfaces

Interfaces

The Crash Course

  • An interface, in general terms, is the things that something provides for the outside world to use.
  • C# has an interface concept that works very much like a class, specifically a pure abstract base class—that is, an interface is a set of methods or properties that any class that uses or "implements" the interface must provide.
  • To create an interface, you simply use the interface keyword where you would previously have used the class keyword.
  • Methods and properties of an interface do not need to be declared abstract or public, because both are assumed to be the case (and in fact are required).
  • To make a class use an interface, you list the class in the same way as you would a base class: class ImplementingClass : Interface { /* put the interface's methods here, as public methods */ }
  • You can implement multiple interfaces, or derive from a single base class and implement any number of interfaces, but you cannot derive from multiple base classes.

Introduction

In this final tutorial about object-oriented programming, we'll discuss interfaces in C#. An interface is very similar to the abstract base classes we saw in the previous tutorial. We'll start off with a discussion of what an interface is, and look at how to actually create an interface. We'll finish up with a brief discussion about multiple inheritance, why C# doesn't support it, and how interfaces allow us to get most of the same effect.

What is an Interface?

An interface, at a conceptual level, is basically just the kinds of things an object presents to the outside world to interact with it. Your TV, for instance, probably has several buttons on it (and if it is really old, maybe even a dial or two). Each of these things allows the outside world to interact with it. The object's interface is its contract to the world that it can do certain things. (Which, by the way, is why it is frustrating when an elevator has a "Close Door" button, but it doesn't actually work. It should work, gosh darn it! There's a button for it and everything!)

C# has a construct built into it called an interface that does this same thing, listing a set of methods that a class that uses the interface is committed to providing.

Interfaces are very similar to the abstract base classes we already looked at. In fact, imagine you had an abstract base class, where every single one of the methods it created was abstract (provided no implementation), and the class had no instance variables or properties. You've basically got an interface! (In the C++ world, this is called a "pure abstract base class"—they have no built-in interface construct.)

Creating an Interface

Creating an interface is actually very similar to creating a class. As an example, let's say our program has a need to write out files (something we'll discuss more in the next tutorial, actually) but you want to be able to write to lots of different file formats. We can create different classes for all of the different kinds of file writers we have (one for each type of file we want to). But they are all going to do basically the same thing, at least as far as the calling code is concerned. They'll all have the same interface.

To model this, we can create an interface in C# for file writers:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace CSharpCrashCourse
{
    public interface FileWriter
    {
        string Extension { get; }
 
        void Write(string filename);
    }
}

This is very similar to a class, with a couple of small differences. One, we use the interface keyword, instead of the class keyword. Two, as you can see, all of our methods and interfaces look like the abstract methods we talked about in last tutorial, and they don't have a method body. But notice that we also don't have to say virtual. Nor do we say that it is public (or private or protected for that matter). Since this is an interface, we already know that the methods are going to be left unimplemented, and we also know that the methods must be public.

Now, we can go ahead and create classes that use this interface.

So we might have a text file writer:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace CSharpCrashCourse
{
    public class TextFileWriter : FileWriter
    {
        public string Extension
        {
            get
            {
                return ".txt";
            }
        }
 
        public void Write(string filename)
        {
            // Do your file writing here...
        }
    }
}

To make a class use or "implement" an interface, we use the same notation that we used for deriving from a base class. We use the colon (':') followed by the name of the interface that we're using.

Inside of the class, we must create a public method with the same return type, name, and parameter list as the interface has.

We, however, are allowed to create additional methods, properties, and instance variables as needed. We're not limited to what the interface defines, we're just required to have that at a minimum.

In most ways, an interface will work in the same way that a base class does. For instance, we can have a list of our FileWriter interface, and put different types of objects that implement the FileWriter interface in it:

FileWriter[] fileWriters = new FileWriter[3];
fileWriters[0] = new TextFileWriter();
fileWriters[1] = new RtfFileWriter(); // we haven't implemented this type anywhere, yet
fileWriters[2] = new DocxFileWriter(); // we haven't implemented this type anywhere, either
 
foreach(FileWriter fileWriter in fileWriters)
{
    fileWriter.Write("path/to/file" + fileWriter.Extension);
}

Many people name their interfaces starting with a capital I. In fact, as you use the standard C# libraries that Microsoft made, you'll see a great deal of things like IEnumerable and IList. My personal preference, again, is not to use them, for readability issues, as I've said before, but this is particularly prevalent. So for one, you'll definitely see it, and two, feel free to use it, as you desire, to fit in with a lot of the other people out there who use it.

Multiple Inheritance, and Why C# Doesn't Support It

In some programming languages, you have the ability to create a class that is derived from multiple base classes. Say, for instance, you have a Person class, which provides things like a name and age, and a NoiseMaker class, which has a method called RaiseTheRoof() (that means "make a lot of noise", in case you didn't know). But then you have a Musician class, which is both a person, and a noise maker. Your first reaction might be to make the class have both Person and NoiseMaker as base classes.

Doing this is called multiple inheritance, and C# doesn't allow it. You have to choose only one to derive from.

Now, I'm not going to go into the details about why C# doesn't allow it (that's pretty big discussion by itself) but suffice it to say that there's a lot of complications that come up when you do that. So while C++ allows multiple inheritance, Java and C# both have opted to only allow you to derive from a single base class.

However, C# does let you implement as many interfaces as you want. You just need to add in all of the methods that each and every one of your interfaces require. You are also allowed to inherit from a single base class, and implement interfaces as well.

So one way around the Person, NoiseMaker, Musician problem we described would be to make Person and NoiseMaker interfaces, and allow Musician to implement both. Or make Person a class, but have NoiseMaker be an interface, and you're still good. Or the other way around.

To implement multiple interfaces, or derive from a base class and multiple interfaces, you simply list them, separated by commas:

public class Musician : Person, NoiseMaker
{
    // ...
}

The C# compiler will check to enforce that your class isn't trying to derive from more than one base class.

What's Next?

We've got one more topic to talk about, regarding classes. It's a cool and powerful feature called generics, which is a way to make classes that can be reused to contain any type of data we want. (It's generic!) We'll start by taking a deeper look at why we would want them, and how to use a few built-in classes that use generics, and then we'll look at how to make our own!