Understanding Interfaces in C#



Abstract
Interfaces are a very useful tool built into C#. In this article Brendan explains the basics of how interfaces work and for what they may be used. He explains how to create simple custom interfaces and how to implement them.

by Brendan Enrick
Feedback



Introduction

What Interfaces Are

Interfaces basically define a blueprint for a class or a struct. The programmed definition of an interface looks very similar to a class, but nothing is implemented. Interfaces define the properties, methods, events, and indexers, but the interface does not define the implementation of any of these. It just declares their existence. Interfaces will not actually define any functionality. They just define ways in which interactions with a class takes place.

What Interfaces Are Not

Interfaces should not be confused with inheritance. They are two very different things. Inheritance will define a lot of the implementation and is used for code reuse. Interfaces are merely a definition for how communication with the implementing classes must take place. It is like a written contract. A class "signing" the contract will agree to perform certain specified actions in any way it wishes, but it must perform the specified actions.

When to Use Interfaces

Interfaces allow us to create nice layouts for what a class is going to implement. Because of the guarantee the interface gives us, when many components use the same interface it allows us to easily interchange one component for another which is using the same interface. Dynamic programs begin to form easily from this.

Creating an Interface

There are times when you will want to define your own interface. When this situation arises you are probably trying to architect software in such a way as to allow change easily later on. Interfaces are a great tool for scaling software projects. When you define an interface it is done similarly to a class. You give it a name and the contents of the interface are between two curly braces. The contents will be methods, properties, events, and indexers. These components are what the interface is requiring be included in any classes implementing the interface.

Listing 1: IHelloWorlder Definition

interface IHelloWorlder
{
  void SayHello();
  void SayGoodBye();

As you can see I have not actually defined any functionality here. All I have done is said what functionality a class using this interface needs to implement. You'll want to note the name I've used here. It is common practice to prefix interface names with an I. Some examples of this practice can be seem with the following interfaces; IDisposable, IDataReader, and IEnumerable. I am sure everyone reading this has used at least one of the interfaces without knowing it. There are plenty of commonly used classes which implement these interfaces.

Implementing an Interface

Now that we know how to create an interface we will look at how to implement one for a class we write. We could implement an existing interface or one which we have created.

In order to say that we will be implementing an interface in our class we only need to specify it on the same line as our class name following a colon ":" symbol. It looks exactly the same as if we were inheriting from a class.

Listing 2: Implementing an Interface

public class MyHelloWorld : IHelloWorlder
{
}

Since we have defined two methods in our IHelloWorlder interface we will need to make sure that we define these two methods in our class. This is part of the agreement we make with the interface when we define a class. We agree to implement anything it says to implement. This lets our new class act in a similar fashion to the other classes using the interface. If we do not define these methods, Visual Studio will give us a message like this one.

Figure 1

As you can see Visual Studio is requiring that we define these two methods that we agreed to implement when we specified our interface. It is at this point that we will go ahead and write implementations for these two methods we agreed to implement. As you can see because interfaces require certain components of the class to exist it makes it so that different classes may be used interchangeably.

Listing 3: Defining the Methods

public class MyHelloWorld : IHelloWorlder
{
    public void SayHello()
    {
        Console.WriteLine("Hello world!");
    }
 
    public void SayGoodBye()
    {
        Console.WriteLine("Good Bye World!");
    }
}

Now that we have defined the two methods of the interface, Visual Studio will allow us to build successfully. We now have a working implementation of the IHelloWorlder class. We can now take a look at how we will use this interface in our program.

Using Interfaces

Now that we have an interface implemented we can take a look at how we can actually use this interface. One nice thing we can do now when writing a method which will just be calling our interface's methods is that we can have it take the interface instead of the class. Observe the following example.

Listing 4: Using an Interface as a Parameter

public void GreetEveryone(IHelloWorlder hw)
{
    // Perform whatever logic you wish here
    hw.SayHello();
}
 
public void DoSomething()
{
    MyHelloWorld helloWorld = new MyHelloWorld();
    GreetEveryone(helloWorld);
}

If we were to write another class implementing the IHelloWorlder we could alter the DoSomethingMethod and change it to use the new class. Since we just specified the interface in the GreetEveryone method we will not have to change anything in there. A good example of when this type of scaling might occur can be seen with the IDataReader interface.

As an example, pretend that we have a web site and that the web site uses XML files to store all of its data. We use an XmlDataReader to read all of the data from the XML files. Since we have used IDataReader in the program instead of always specifying XmlDataReader everywhere, we can easily change to using a database later. We would be able to change to using a SqlDataReader for example. We will have less code to change because we are using the IDataReader interface and both classes implement it so a lot of the interaction remains the same. If we were to then decide we wanted a different type of database we could easily switch to another IDataReader-implementing class and continue working.

Conclusion

We are able to write these interfaces which are basically just a blue print or a contract defining how interaction will take place with certain classes. Implementing an interface is as easy as fleshing out a class by defining the specified methods, properties, events, and indexers. When we want to use an interface in our code we just define it as if it was a class name, and then we use any class which implements the interface as if it were the interface. By using interfaces we make our code much more maintainable and more dynamic.

Author's Blog

Brendan Enrick

posted on 2008-01-25 12:43  josephshi  阅读(104)  评论(0编辑  收藏  举报