Click here to Skip to main content
15,867,141 members
Articles / Programming Languages / C#
Article

The Interface Construct in C#

Rate me:
Please Sign up or sign in to vote.
4.77/5 (86 votes)
31 Oct 20078 min read 301.9K   4.8K   171   33
Using interfaces as a means to decouple classes, making your application more flexible.

Table of Contents

Abstract

This article describes the use of the interface construct in C#. Using interfaces is an important part of developing flexible software. An interface provides indirection between communicating classes. Indirection because the client class, using a service provided in another class, does not have to know anything about the service class except that it is implementing an interface. The client class can use a service provided by any class implementing the required interface.

Introduction

This article shows the benefits that can be obtained when deriving from interfaces in .NET.

The Term Interface

To speak the same language it is important that we understand what an interface is since the word interface has a different meaning based on the context it is used in. The word interface is often used to describe the public parts of a class, i.e. the part that can be seen from others classes. The graphical user interface (GUI) is another use of the word interface. This article will describe the C# interface construct.

The Interface Construct

An interface is a construction similar to an abstract class but with no implementation code. That is, an interface is only composed of method declarations, indexers, events and constants. This article only deals with method declarations. An interface can be used anywhere in the class design as instance variables or parameters in method signatures. An interface is a contract defining that any class that implements an interface must implement all the method definitions given in the interface. An interface says what a user of the interface must do, but not how to do it. An interface defines behavioral characteristics and places those behaviors in classes independent of the class hierarchy. When a class makes a contract by applying an interface, the class is said to implement the interface or inheriting from the interface. This article uses the phrase: Implement an interface.

Example of an Interface and Implementation

There is no implementation code present, only method signatures. An implementing class must write the body code for the two methods:

C#
public interface IPerson
{
  string GetName()
  void SetNAme(string name)
}

It is common to use the prefix 'I' in front of an interface name, but it is not required. It makes it easier to read and understand the design illustrated whether it is a UML class diagram or a bunch of source files that you got from a third party.

And the service code implementing the interface is:

C#
public class APerson: IPerson
{
  string name;

  private string GetName()
  {
    return name;
  }
  private void SetName(string name)
  {
    this.name = name;
  }
}

Multiple Interface Inheritance

A class only inherits from one class in C#, but can implement (inherit) as many interfaces as needed.

Interface use in Polymorphism

Class and interface polymorphism is basically the same thing. The type (Room) of the variable (r1) and the type of the object (LivingRoom) stored in it is not exactly the same.

C#
Room r1 = new LivingRoom()

The Room type is said to be of static type and the LivingRoom type is said to be of a dynamic type or subtype. The smart thing about using polymorphism is, among other factors, that you can wait until runtime to decide what type to use for your variable. Because of this, polymorphism is also called late binding. An interface does not have a constructor so one can only create an object of an interface as a subtype. Use of interfaces as instance variables have to be as a subtype of the classes implementing the interface.

Diagram of the Interface Logic

Screenshot - InterfaceConstruct1.jpg

A class should not have too many responsibilities (some say three is a maximum). A Client class can delegate responsibilities or services to an interface. The service is provided by a ServiceProvider who is implementing the interface. The Client class and the ServiceProvider class only communicate through the interface. The client and the service provider do not know about each other (indirection). Every service provider who is implementing the interface is accepted by the client, making the use of interfaces a flexible programming tool.

Design Pattern

The condensed description of design pattern is: a solution to a problem in a certain context. One of the first formal descriptions of design pattern was the GoF book (1995). The GoF (Gang of Four) described a basic rule of reusable object-oriented design: "Program to an interface, not an implementation." Grand (2002) makes the use more formal by declaring a basic design pattern called an Interface Pattern. Grand defines an interface pattern because the interface construct is present in many design patterns, giving flexibility and reusability to the construction of software.

An Example Using Interfaces

In the example below three different graphical user interfaces (here the word interface is used about the user interface and not the interface construct) are used to present the result of three different ways of reading a file. The client classes of the code sample are: BlueGUI, RedGUI and YellowGUI. The three other classes providing a service reading different file types. The provided services are the classes: XMLInput (reading an XML file), INIInput (reading an INI/text file) and BinInput (reading a binary file). The three client classes and the three services providing classes communicate indirectly through an interface called IInput. This gives the flexibility of nine possible combinations when building an application. The purpose of this article is not to show how to read XML, INI text files or binary files, but to show how to use an interface as a means of indirection between communicating sets of classes.

Screenshot - InterfaceConstruct2.jpg

Class diagram shows the relationship between the three client classes (colour GUIs) and three service providing classes (input readers). The three client classes are using an instance of the interface and the three service providers are implementing the interface. Sub-typing the three implementing classes of the interface is used to indirectly attach the client and service provider, in a driver class. In the sample code checkboxes are used to select the two classes to couple from the two set of classes.

The interface code:

C#
//The interface IInput is responsible handling string information.
public interface IInput
{
  // Returns a string value from a service
    string NotifyOutput();
}

The RedGUI class:

C#
// The RedGUI is a form class using the IInput
// interface through the object input.
public class RedGUI : System.Windows.Forms.Form
{
    IInput input;

    public RedGUI(IInput input)
    {
        this.input = input;
        this.BackColor = System.Drawing.Color.Red;
        this.Show();
    }

    public void GetInput()
    {
        this.Text = input.NotifyOutput();
    }
}

The BlueGUI class:

C#
// The BlueGUI class is a parallel to the RedGUI class.
public class BlueGUI : System.Windows.Forms.Form
{
    IInput input;

    public BlueGUI(IInput input)
    {
        this.input = input;
        this.BackColor = System.Drawing.Color.Blue;
        this.Show();
    }

    public void GetInput()
    {
        this.Text = input.NotifyOutput();
    }
}

The YellowGUI class:

C#
// The YellowGUI class is a parallel to the RedGUI class.
public class YellowGUI : System.Windows.Forms.Form
{
    IInput input;

    public YellowGUI (IInput input)
    {
        this.input = input;
        this.BackColor = System.Drawing.Color. Yellow;
        this.Show();
    }

    public void GetInput()
    {
        this.Text = input.NotifyOutput();
    }
}

The XMLInput class:

C#
// XMLInput reads some elements from an xml file.
// XMLInput is a subtype of the interface IInput.
public class XMLInput : IInput
{
    // An empty constructor
    public XMLInput() {}

    // Implementation of interface
    public string NotifyOutput()
    {
        return ReadXML();
    }

    // Simple read of an XML file
    public string ReadXML()
    {
        string str = "";
        try {
            XmlDocument doc = new XmlDocument();
            string xmlFile = System.Windows.Forms.Application.StartupPath +
                                                             "\\input.xml";
            if (System.IO.File.Exists(xmlFile)){
                doc.Load(@xmlFile);
                XmlNodeList node1 = doc.GetElementsByTagName("node2");
                foreach(XmlNode node2 in node1){
                    str += node2.ChildNodes[0].FirstChild.Value;
                }
            }
            else {
                Console.WriteLine("Missing the input.xml from" +
                                         " application directory.");
            }
        }
        catch (Exception e) {
            Console.WriteLine(e.Message);
        }
        return str;
    }
}

The INIInput class:

C#
// INIInput reads some elements from a simple ini text file.
// INIInput is a subtype of the interface IInput.
public class INIInput : IInput
{
    // An empty constructor
    public INIInput() {}

    // Implementation of interface
    public string NotifyOutput()
    {
        return ReadIni();
    }

    private string ReadIni()
    {
        string str = "";
        string iniFile = System.Windows.Forms.Application.StartupPath +
                                                          "\\input.ini";
        try {
            if (System.IO.File.Exists(iniFile)){
                using (StreamReader sr = new StreamReader(iniFile))  {
                    String line;
                    while ((line = sr.ReadLine()) != null) {
                        str += line;
                    }
                }
            }
            else {
              Console.WriteLine("Missing the input.ini " +
                                        "from application directory.");
            }
        }
        catch (Exception e) {
            Console.WriteLine(e.Message);
        }
        return str;
    }
}

The BinInput class:

C#
// BinInput reads a string from a string object in a binary file.
// BinInput is a subtype of the interface IInput.
public class BinInput : IInput
{
  public BinInput() { }

  // Implementation of interface
  public string NotifyOutput()
  {
    return ReadBin();
  }

  public string ReadBin()
  {
    AStringClass SomeStringClass = null;
    string binFile = System.Windows.Forms.Application.StartupPath +
                                                      "\\input.bin";
    try {
      if (File.Exists(binFile)){
        IFormatter formatter = new
          System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
        Stream stream = new FileStream(binFile, FileMode.Open,
                                         FileAccess.Read, FileShare.Read);
        SomeStringClass = (AStringClass) formatter.Deserialize(stream);
        stream.Close();
      }
      else {
        Console.WriteLine("Missing the input.bin" +
                                    " from application directory.");
      }
    }
    catch (Exception e) {
      Console.WriteLine(e.Message);
    }
    return SomeStringClass.SomeString;
  }
}

// We need this class to cast the serialized objects from the stream,
// when we read the input.bin file. Is also used to
// create the binary file.
// The create of the binary file is not used in this sample instead the
// input.bin file is coming with the source code.
[Serializable]
public class AStringClass
{
  public string SomeString;

  public AStringClass()
  {
    this.SomeString = "Text from a bin file";
    string binFile = System.Windows.Forms.Application.StartupPath +
                                                       "\\input.bin";
    SaveToBinaryFile(binFile);
  }

  public void SaveToBinaryFile(string binFile){
    try {
      IFormatter formatter = new
        System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
      Stream stream = new FileStream(binFile, FileMode.OpenOrCreate,
                                       FileAccess.Write, FileShare.None);
      formatter.Serialize(stream, this);
      stream.Close();
    }
    catch (Exception e) {
            Console.WriteLine(e.Message);
    }
  }
}

The driver is the master code using all the previous written classes and interface. This is where all the classes are related to each other:

C#
// Input XML file to Blue GUI
IInput input = new XMLInput();
BlueGUI blueGUI = new BlueGUI(input);
blueGUI.GetInput();

// Input XML file to Red GUI
IInput input = new XMLInput();
RedGUI redGUI = new RedGUI(input);

// Input XML file to Yellow GUI
IInput input = new XMLInput();
YellowGUI yellowGUI = new YellowGUI(input);
yellowGUI.GetInput();

// Input INI file to Blue GUI
IInput input = new INIInput();
BlueGUI blueGUI = new BlueGUI(input);
blueGUI.GetInput();

// Input INI file to Red GUI
IInput input = new INIInput();
RedGUI redGUI = new RedGUI(input);
redGUI.GetInput();

// Input INI file to Yellow GUI
IInput input = new INIInput();
YellowGUI yellowGUI = new YellowGUI(input);
yellowGUI.GetInput();

// Input Bin file to Blue GUI
IInput input = new BinInput();
BlueGUI blueGUI = new BlueGUI(input);
blueGUI.GetInput();

// Input Bin file to Red GUI
IInput input = new BinInput();
RedGUI redGUI = new RedGUI(input);
redGUI.GetInput();

// Input Bin file to Yellow GUI
IInput input = new BinInput();
YellowGUI yellowGUI = new YellowGUI(input);
yellowGUI.GetInput();
…

In the Interface Demo application the driver code is controlled by radio buttons. The radio buttons are placed on top of the UML illustration to clarify the class relations.

Screenshot - InterfaceConstruct3.jpg

It is easy to extend the application with new functionalities. If the customer wants a new functionality, say a new service provider reading from another source which is not currently present, the problem is solved by writing a new reader class implementing IInput. This is a good way of extending the system since the developer does not have to change any existing code. Changing existing code could introduce new errors. A rule can be expressed as: "Once written don't change." Also, if the original developer is busy with other jobs, the job of implementing the new functionality can be given to his colleague. The colleague who does not know the design and perhaps does not have the time to understand it, just writes a class capable of reading the new file format, so all that the new developer has to do extra is to implement the IInput interface. The original developer can then easily implement the new class in the system.

Casting with the 'as' or 'is' Operator

As a final note on interfaces a word on the as and is operators could be useful. Objects can be referenced by casting an object to one of its implemented interfaces. The new object can then call those interface members. This is the reverse process of the above driver code.

C#
iInput = xmlInput as IInput;
if (null != iInput)
…

The as operator checks if both the types are compatible and casts xmlInput to iInput. The is operator only checks if the two types are compatible.

Disadvantage

One drawback of using interfaces is that it makes the code more complicated to understand.

Points of Interest

The major advantage of using interfaces is that you add an extra dimension of communication to your design. Instead of only accessing classes through class inheritance, with interfaces you can make a backdoor open for classes implementing a specific interface. This construct makes the software flexible for future changes. The client using your class through a method argument or instance variable will not have to know anything about the class, but that it implements a specific interface. Meaning: all classes implementing a given interface can be used. Uses of the interface construct decouple your design resulting in low coupling and high cohesion. Low coupling means that when classes are decoupled they do not depend closely on each other. The chance of failures, faults or errors getting thrown when you make changes to existing code will be lower when the classes are decoupled. Often you do not have to change existing code. All you do is add new code. Design of interfaces and their use in design patterns is at a more abstract level compared to the abstract level where your code is at. In fact, design patterns and the use of interface abstracts the code itself. Meaning that if you have your design ready you can make the source code either in Java or C# directly from the design. This also means that when you are looking for literature on design pattern, and use of interface constructs, Java books are fine too. The best books (besides the GoF) on design pattern are still the Java ones.

History

  • 2005-04-24 - First edition.
  • 2007-10-30 - Minor updates.

Literature

  • Grand, M. (2002): Design Patterns in Java. Volume 1. Wiley Publishing, Inc.
  • Gamma, E., Helm, R., Johnson, R. and Vlissides, J. alias GoF (1995): Design Patterns. Elements of Reusable Object-Oriented Software.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Denmark Denmark
I am working as a software developer for COWI Engineers and Planners since year 2000, http://www.cowi.dk.

My main area of development is GIS (Geographical Information Systems) software using C# and Delphi with the mapping tools: MapXtreme 2004/MapBasic/MapInfo.


Comments and Discussions

 
GeneralMy vote of 5 Pin
doktorfeelgood14-May-17 15:26
doktorfeelgood14-May-17 15:26 
PraiseGreat Pin
Yusuf Yazıcı9-Feb-16 22:36
Yusuf Yazıcı9-Feb-16 22:36 
GeneralMy vote of 5 Pin
Mahsa Hassankashi29-Sep-14 4:27
Mahsa Hassankashi29-Sep-14 4:27 
QuestionHere is another practical example: Pin
dietmar paul schoder2-Aug-14 10:25
professionaldietmar paul schoder2-Aug-14 10:25 
GeneralMy vote of 5 Pin
hari111r5-Dec-12 19:18
hari111r5-Dec-12 19:18 
AnswerWrite a program in C# to implement Multiple Interfaces in a Single class. Pin
Member 964663030-Nov-12 19:46
Member 964663030-Nov-12 19:46 
QuestionMy Vote of 5 Pin
kavitharavi25-Oct-12 0:11
kavitharavi25-Oct-12 0:11 
GeneralMy vote of 5 Pin
GuyThiebaut9-May-12 4:46
professionalGuyThiebaut9-May-12 4:46 
QuestionVery clear and useful article Pin
Steggs1117-Mar-12 20:17
Steggs1117-Mar-12 20:17 
GeneralMy vote of 4 Pin
karthik cad/cam30-Apr-11 2:50
karthik cad/cam30-Apr-11 2:50 
GeneralMy vote of 2 Pin
Lou Arnold13-Apr-11 9:46
Lou Arnold13-Apr-11 9:46 
GeneralRe: My vote of 2 Pin
Thesisus20-Jul-11 6:51
Thesisus20-Jul-11 6:51 
GeneralYour demo program does not demonstrate the point of the article. [modified] Pin
Lou Arnold13-Apr-11 9:43
Lou Arnold13-Apr-11 9:43 
GeneralMy vote of 5 Pin
adriancs4-Apr-11 16:19
mvaadriancs4-Apr-11 16:19 
GeneralMy vote of 5 Pin
o1010wanabe10-Oct-10 9:21
o1010wanabe10-Oct-10 9:21 
Generalbig thx Pin
lgeyer31-Jul-10 6:00
lgeyer31-Jul-10 6:00 
Generalnice Article Pin
Su_shamim25-Jan-10 20:43
Su_shamim25-Jan-10 20:43 
GeneralExplicit implementation Pin
Georgi Atanasov31-Oct-07 23:12
Georgi Atanasov31-Oct-07 23:12 
Hello,

Nice article, shows important concepts!

One thing I have noticed from a first read:

In your example of implementing an interface the GetName and SetName methods should be either public (implicit implementation) or explicit like this:

private string IPerson.GetName()
{
}
private void IPerson.SetName(string name)
{
}

Otherwise the code will not compile.

Thanks,
Georgi

GeneralClarification needed Pin
PIEBALDconsult18-Aug-07 5:52
mvePIEBALDconsult18-Aug-07 5:52 
GeneralRe: Clarification needed Pin
Jakob Lanstorp30-Oct-07 0:09
Jakob Lanstorp30-Oct-07 0:09 
GeneralThe Benefit of the Talent Pin
grivix18-Aug-07 5:09
grivix18-Aug-07 5:09 
GeneralRe: The Benefit of the Talent Pin
Jakob Lanstorp30-Oct-07 0:06
Jakob Lanstorp30-Oct-07 0:06 
GeneralExcelent Work Pin
Rahul8314-Jun-07 0:35
Rahul8314-Jun-07 0:35 
GeneralRe: Excelent Work Pin
Jakob Lanstorp30-Oct-07 0:03
Jakob Lanstorp30-Oct-07 0:03 
GeneralThank you Jakob Pin
vediyarasu8-Jul-06 5:28
vediyarasu8-Jul-06 5:28 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.