Click here to Skip to main content
Click here to Skip to main content

Interface based programming in C#

By , 30 Dec 2013
Rate this:
Please Sign up or sign in to vote.

Introduction

Interface is one of the more overloaded and confusing concepts in object oriented programming. This article can help to understand Interfaces for those who have just started programming.

What is an Interface in C#?

Let’s start with the short definitions for Interface:

  • An Interface is a way to achieve runtime polymorphism in C#.
  • An Interface is a collection of properties and methods declarations.
  • An Interface is a type declaration like a class or structure in C#; an Interface itself does not implement members.
  • Interfaces are contract templates in which the contract members are declared.

What are the characteristics of an Interface?

Interfaces cannot be initialized directly as they do not have a definition for members, they should be implemented by either a class or structure.

Interfaces can contain any of the following type members or a combination of these four member types.

  1. Property
  2. Method
  3. Event
  4. Indexer

An Interface can be declared as either public or internal inside a namespace and can’t have any other access modifiers. An Interface can have any access modifier when declared inside a class or structure.

Members of an Interface are public by default and can’t have other access modifiers.

A class implementing an Interface must implement all the members declared in the Interface and they must be marked as public in the Implicit implementation. In the case of Explicit implementation, the Interface members can't have any access modifiers and they are private by default. If the implementing class is signed as abstract then the members of the Interface can also be signed as abstract in the class.

Why should we use Interfaces in C#?

Let’s start with a real world scenario to understand the Interface implementation.

Consider an application with a logging module to log application errors; the application should be able to address a customer specific error logging method. On the customer's side, Client A may expect the application to write logs to the file system, Client B may expect to log errors in the database, and Client C may go for the Windows Event log.

To address the above scenario, the application design should support swapping of the logging system with less or no developer effort, and this leads to writing a plug-n-play like module for the application.

We can address this scenario with a flexible and extensible software design using Interfaces. The rest of the article will deal with developing the system with notes on handling Interfaces in C#.

How to implement an Interface

Interface declaration

An Interface needs to be declared before it can be implemented in any class. An Interface can be declared inside a namespace or a class with the keyword interface followed by the Interface name.

Example
namespace LoggingModule.Contract
{
    public interface ILogger
    {
        /// <summary>
        /// Write log information to logging source.
        /// </summary>
        void WriteLog(String Message);
    }
}

In the above code, we have declared an Interface called ILogger with a single method WriteLog inside the namespace LoggingModule.Contract. As the name implies, the WriteLog method will have code for writing log information to the configured logging source.

Interface implementation

A class can implement an Interface by suffixing a colon followed by the Interface name. A class can implement multiple interfaces by separating the Interface names with a comma.

Example
namespace FileSystemLoggingModule
{
    public class FileSystemLogger : ILogger
    {
        public void WriteLog(string Message)
        {
            Console.WriteLine(Message + " ==> File system Logger is invoked!");
        }
    }
}

The above code shows the implementation of a single Interface ILogger in the FileSystemLogger class. The WriteLog method is defined with the same input parameters and return type (void) as declared in ILogger.

In the same way we can create a class for database logging and Windows EventLog logging as shown below. All these three classes have implemented the contract ILogger which is demanding the implementation of the WriteLog method.

namespace DatabaseLoggingModule
{
    public class DatabaseLogger: ILogger
    {
        public void WriteLog(String Message)
        {
            Console.WriteLine(Message + " ==> Database Logger is invoked!");
        }
    }
}

namespace WindowsEventLoggingModule
{
    public class WindowsEventLogger: ILogger
    {
        public void WriteLog(string Message)
        {
            Console.WriteLine(Message + " ==> Windows event logger is invoked!");
        }
    }
}

Now, let’s see how to use this interface in an application. We have declared an Enum (LoggingType) to expose the available logging types.

The ApplicationLogger class has a LogError method which will check the logging type configuration and load the appropriate logger implementation.

public enum LoggingType
{
    FileSystem = 1,
    Database = 2,
    WindowsEventLog = 3
}
Code for loading logger based on logging type
namespace LearningInterface
{
    public class ApplicationLogger
    {
       public void LogError(String strMessage)
        {
            LoggingType ConfiguredLoggingType = (LoggingType) 
              Convert.ToInt32(ConfigurationManager.AppSettings["LoggingType"]);

            ILogger Logger;

            switch (ConfiguredLoggingType)
            {
                case LoggingType.FileSystem:
                    Logger = new FileSystemLogger();
                    break;
                case LoggingType.Database:
                    Logger = new DatabaseLogger();
                    break;
                case LoggingType.WindowsEventLog:
                    Logger = new WindowsEventLogger();
                    break;
                default:
                    Logger = null;
                    break;
            }

            if (Logger != null)
            {
                Logger.WriteLog(strMessage);
            }

        }
    }
}

The LogError method reads the logging type value in the app settings from web.config. The ILogger object is initialized based on the logging type set in app settings. By initializing ILogger based on configuration settings, we can easily switch the logging type of the application. If we need to change the logging type in future, we don’t need to edit or recompile the application; changing LoggingType key in web.config will switch the application logging process. A new logging type can be added to the application easily in the same way we did for the database, Windows Event loggers.

There are better ways to achieve plug-n-play like software design with Interfaces and IoC. I have chosen the above approach to make it simpler to understand for beginners in C#.

Types of Interface implementation

An Interface implementation can be either Implicit or Explicit. In this article, we have used implicit Interface implementation.

Explicit implementation allows developers to tag the implementation details explicitly to the Interface. Explicitly implemented members are prefixed with the Interface name as shown below.

namespace LearningInterface
{
    public class ExplicitImplementation: ILogger, IErrorLogger
    {
        void ILogger.WriteLog(string Message)
        {
            Console.WriteLine(Message + " ==> Explicit implementaion of ILogger.WriteLog() invoked.");
        }

        void IErrorLogger.WriteLog(string Message)
        {
            Console.WriteLine(Message + " ==> Explicit implementaion of IErrorLogger.WriteLog() invoked.");
        }
    }
}

You will notice that, there are two implementations of the WriteLog method with the prefix of the respective Interface names. Explicit implementation helps identify the members more accurately and avoid shadowing/collision of members in multiple Interface implementations.

You can explicitly implement an Interface in Visual Studio as shown below:

Let’s see a scenario where we need to implement an Interface explicitly.

We know that C# does support multiple Interface implementations in a class. Our application has two interfaces: ILogger and IErrorLogger, for different purposes, and have a method called WriteLog() with identical signature declared in those two interfaces. Now we have to implement those two Interfaces in a class.

First, we shall implement these Interfaces implicitly and see the problem with it.

Interfaces can be implemented implicitly in visual studio as shown in below.

Clicking on “Implement interface ‘ILogger’ will generate a skeleton of ILogger members as shown below and can build successfully.

Let’s modify WriteLog() to test it.

namespace LearningInterface
{
    public class ImplicitImplementation: ILogger, IErrorLogger
    {
        public void WriteLog(string Message)
        {
            Console.WriteLine(Message + " ==> Implicit implementaion of WriteLog() invoked.");
        }
    }
}

The above code shows the implicit implementation of ILogger and IErrorLogger in the ImplicitImplementation class. This code will build with no errors as the WriteLog() implementation is compromising both ILogger and IErrorLogger. Doing this way will spoil the purpose of interfaces as we have defined the same behavior for both Interfaces. So, we need to have an option to identify or name Interface members explicitly.

Let’s invoke WriteLog() from ILogger and IErrorLog objects and analyze the output.

Console.WriteLine("Implicit implementaion of an Interface in C#" + Environment.NewLine);

ImplicitImplementation objImplicit = new ImplicitImplementation();

//Create ILogger object
objLogger = (ILogger)objImplicit;

//Create IErrorLogger object
objErrorLogger = (IErrorLogger)objImplicit;

objLogger.WriteLog("Invoking from ILogger");

objErrorLogger.WriteLog("Invoking from IErrorLogger");

Console.ReadLine();

In the above code, we have created an object of the ImplicitImplementaion class and created ILogger and IErrorLogger objects from it. ILogger and IErrorLogger objects are invoking the WriteLog() method.

Output

When you run the code, you will get an output as shown above. Both Interfaces are invoking the same method.

This is not the expected behavior, ILogger and IErrorLogger must implement the WriteLog method differently and we should be able to invoke a specific implementation of the WriteLog method.

Let’s see how we can achieve it with an explicit implementation of ILogger and IErrorLogger.

Console.WriteLine("Explicit implementaion of an Interface in C#" + Environment.NewLine);

ExplicitImplementation objExplicit = new ExplicitImplementation();

//Create ILogger object
objLogger = (ILogger)objExplicit;

//Create IErrorLogger object
objErrorLogger = (IErrorLogger)objExplicit;

objLogger.WriteLog("Invoking from ILogger");

objErrorLogger.WriteLog("Invoking from IErrorLogger");

Console.ReadLine();

We have implemented the WriteLog method for both interfaces with the prefix of the respective Interface names in the ExplicitImplementaion class. An object for the ExplicitImplemenatation class is created and type casted to generate ILogger and IErrorLogger objects.

So, when we invoke Logger.WriteLog(), void ILogger.WriteLog(int ErrorCode, string Message) of ExplicitImplementaion should be invoked. In same way, IErrorLogger.WriteLog(int ErrorCode, string Message) should be invoked when ErrorLogger.WriteLog is executed.

Output

As you can see in the output, we are able to identify and invoke specific implementations of WriteLog() for ILogger and IErrorLogger.

Difference between explicit and implicit implementations

Implicit implementation
  1. Members are public by default.
  2. Members must be marked as public.
  3. Members can be invoked directly through the object of the implementing class.
  4. Example:

    FileSystemLogger objFileSystemLogger = new FileSystemLogger();
    objFileSystemLogger.WriteLog("");
Explicit implementation
  1. Members are private by default.
  2. Members can't have any access modifiers.
  3. Members can't be accessed directly, an object of the implementing class should be cast to the Interface type to access the members.
  4. Example:

    FileSystemLogger objFileSystemLogger = new FileSystemLogger();
    ILogger objLogger = (ILogger)objFileSystemLogger;
    objLogger.WriteLog("");

Points to consider while designing Interfaces

  1. An Interface should focus on common and related tasks that a module expects. Inclusion of unrelated methods will ruin the purpose of the Interface.
  2. An Interface should not include any method which is specific to a class; if there are specific methods declared in the Interface, it will become hard to implement the same Interface for other classes.
  3. An Interface should not declare too many methods. Too many methods make the implementation of Interfaces harder as the implementing class needs to implement all methods declared by the Interface.
  4. An Interface should be declared when there is need for abstraction by design. Too many abstractions may lead to increased complexity in maintenance and reusability of code.

Conclusion

Use of Interfaces will result in defining a clear relationship between modules in a system. Using an Interface is a good approach to write maintainable and reusable code in C#. Programming with Interfaces leads to developing a system with extensibility.

In this article, we have seen three different implementations of the logging process. In future if there is a need for switching to some other logging framework such as log4Net, it can be done easily by creating a wrapper class for log4Net which will implement ILogger. There is no need for changing anything in other modules.

I hope that by understanding the examples discussed in this article, developers can understand the flexibility and the power that Interfaces can bring to system design.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Nagaraj Muthuchamy
Software Developer (Senior) Visual BI
India India
Software developer with 8 years experience in developing .NET web applications.
Follow on   LinkedIn

Comments and Discussions

 
QuestionWhy interface? PinprofessionalRhishikeshLathe6-Jan-14 20:03 
AnswerRe: Why interface? PinprofessionalNagaraj Muthuchamy6-Jan-14 20:12 
GeneralRe: Why interface? PinprofessionalRhishikeshLathe6-Jan-14 23:02 
QuestionNo edit or re-compile Pinmemberbojammis30-Dec-13 7:59 
GeneralMy vote of 3 PinprofessionalJanty26-Dec-13 23:39 
GeneralRe: My vote of 3 PinmemberThomas Maierhofer (Tom)30-Dec-13 10:56 
QuestionGood one!! Pinmemberhiren2.p26-Dec-13 20:53 
QuestionWhat is the main difference of Interface and Abstract ? Pinmemberhemantwithu26-Dec-13 20:22 
AnswerRe: What is the main difference of Interface and Abstract ? PinprofessionalNagaraj Muthuchamy26-Dec-13 21:02 
QuestionMany imprecise statements. PinprofessionalPaulo Zemek26-Dec-13 14:04 
AnswerRe: Many imprecise statements. PinprofessionalNagaraj Muthuchamy27-Dec-13 4:47 
GeneralThoughts PinprofessionalPIEBALDconsult26-Dec-13 11:59 
GeneralRe: Thoughts PinprofessionalNagaraj Muthuchamy27-Dec-13 4:50 
GeneralMy vote of 5 Pinmembermanoj kumar choubey26-Dec-13 9:55 

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

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

| Advertise | Privacy | Mobile
Web01 | 2.8.140415.2 | Last Updated 30 Dec 2013
Article Copyright 2013 by Nagaraj Muthuchamy
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid