Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Interfaces In Action

0.00/5 (No votes)
22 Apr 2012 1  
A basic introduction to interfaces and their usage in development

Introduction

Just recently, I weighed in on a post where the author was making a legitimate complaint about the quality of articles submitted. I won't go into the details, but since that discussion I've been tempted to write my first article as I think I should try my best and contribute more to the community. Today I commented on another authors post, it was well written and I could follow the thread of the article, but the examples were a little too obscure (for my liking), so their real world application might not be immediately apparent to the reader. So, on to my first article.

It took me a while to grasp the concept of interfaces. It's not that they're particularly difficult as a concept, but how and where to apply them is where a developer can struggle. My intent with this article is not to show anything radically different, not to try and say "my article better describes x" but to try and put my understanding of interfaces and their practical implementation into my words, so that the reader has a different perspective with which to view the topic.

Assumptions

I'm going to make the assumption that you understand (not necessarily are a master of) basic object orientated principals and that you are comfortable with the following words.

  • object
  • class
  • property
  • method

What is an Interface

The simplest analogy I can draw for an interface is that of a contract. A landlord of a property might have a standard contract, everybody expecting to live in a property owned by that landlord agrees that they will adhere to the rules and guidelines contained within it. How two tenants keep within that rule set is entirely up to them, but they are both bound by the same contract. An interface is a guarantee that certain behaviors and values will be available to anybody using an object that implements that interface.

Declaration

You define an interface in C# as follows:

public interface ICustomAction<T>
{
     string Name { get;}
     string Description { get; set; }
     T Execute( T val );
}

An interface is always public. You cannot define access modifiers on the properties and methods defined within and you cannot provide any implementation for your interface.

Note: If you are familiar with C# 3.0's features, specifically auto-properties, do not confuse your interface definition with an auto-property. It is not implementation in the case of an interface.

Use

You cannot create an object of an interface, you can only create an object of a class that implements an interface. Although you will see examples such as:

public void MyMethod( ICustomAction<int> action)
{
}

You can never actually declare an object of type ICustomAction. Give it a go, see what happens.

  ICustomAction<int> action = new ICustomAction<int>( );

Instead, you need to define a class and implement the interface, defining the functionality that you have agreed an object implementing this interface will provide.

  public class UpdateOrderAction : ICustomAction<int>
  {
      public string Name 
      { 
          get 
          {
            return "UpdateOrderAction";
          }
      }

      public string Description {get;set;}
      
      public int Execute( int val )
      {
         // 
      }
  }

Not very useful at the moment. However, you've actually created a class from which you can instantiate an object and you will guarantee it provides a name and a method 'Execute'. Notice that we are now able to define access modifiers on the properties and methods defined. You are however, limited to your properties and methods being made public.

Why Only Public?

As I said earlier, when you define an interface, you are making a guarantee that any properties and methods defined on that interface are available on all classes that implement it. Let us say that Jeff and Bill are writing a system together. Bill is going to work on the back end accounting system, Jeff is going to be working on the front end, data entry system. They're starting their development at the same time, so there is no existing code to work from. Jeff will be allowing data entry clerks to create invoices for customers, Bill's back end system will be responsible for posting those invoices to ledgers etc. So, Bill and Jeff sit down and flesh out the rough design of their system, what they'll need from one another. They agree that an invoice should contain:

  • Id
  • CustomerReferenceNumber
  • Value

So, they define an interface:

  public interface IInvoice
  {
      int Id {get;set;}
      int CustomerReferenceNumber {get;set;}
      decimal Value {get;set;}
  }

Now, they both go away happy. Bill knows that he can work with an IInvoice object coming from Jeffs front end, Jeff knows that when he is ready, he can produce an invoice object that implements the IInvoice object they just discussed and he won't hold Bill up. Now, if Jeff decided that when a customer was a high profile customer, he would make the customer reference number private on the invoice, he would not be fulfilling the contract that he and Bill had agreed upon and that the IInvoice interface had promised. So, any class implementing an interface must make all the properties and methods that make up that interface public to all.

Back to the Point

Using the example of the ICustomAction interface from earlier, we'll now continue to try and expand upon implementing our interface in a class. We defined the custom action interface as being of a type, so when we implement the interface in our object, in this case:

  public class MultiplyAction : ICustomAction<int>
  {
       public string Name
       {
             get
             {
                 return "Multiply Action";
             }
       }
       
       public string Description { get; set; }
       public int Execute( int val )
       {
             Console.WriteLine( "Name: {0} Value: {1}", Name, val );
             return val * 2;
       }
  }
  • MultiplyAction - The name of the class into which we put the behavior(implementation) of our interface.
  • ICustomAction<int> - This class will implement the ICustomAction interface and will accept integer types wherever T was specified in our interface declaration.
  • public int Execute( int val) - In the interface, this looked like T Execute( T val). We're now implementing it, so it's time for a solid type.

To see this in work, take a look at the sample source code. The generics I used are a little beyond the scope of this article, but hopefully my example code makes them understandable enough. You could define your ICustomAction like so:

  public interface ICustomAction
  { 
      string Name {get;}
      string Description {get;set;}
      int Execute( int val);
  }  

A Brief Summary

In the attached code, there are three custom actions. One is the manager class that has a list of custom actions attached to it, the others are the actions that we can perform. In the program.cs, I create an object of type ActionManager and I add two custom actions to it. Notice that the code only specifies that an ICustomAction<int> is required, not that a Multiply or DivideAction is required.

When Interfaces Come into their Own

Without trying to throw around a bunch of common phrases (such as dependency injection, loose coupling, etc., few of which I believe I have a strong grasp of) Programming to the interface, rather than a solid implementation of an object gives the developers the flexibility to swap out the actual implementation without worrying too much about how the program will take the new change. Back to Jeff and Bill from before. Now, let us say that Jeff and Bill didn't have their original discussion, let us say that the conversation went something like:

Jeff: Hey Bill, so what do you need from my data entry system?

Bill: Well Jeff, I need to get an invoice, I need an Id, a customer reference number and a value. I can just tie up the customer reference number to the account and then post a value on the ledger.

Jeff: Oh great! I'll pass you an invoice just like that.

So, they go away and a week later, Jeff posts an Invoice object to Bill. Great. The system is working fine and they have got it up and running in record time. Their managers are overjoyed, the business is efficient. A month later, Jeff's manager approaches him.

Manager: Jeff, we have a bit of an issue. We're having trouble reporting on the invoices. Some of our customers have the ability to override on an invoice by invoice basis just what terms they have.

Jeff: Hmmmm

Manager: You'll sort it out, that's great!

So, Jeff goes away and thinks long and hard about this. He decides that the best way of doing this is to create a new type of invoice, a SuperInvoice (don't name your objects super anything!). He gets it done in an hour and then implements the change on the system. *BANG*

Bill: Jeff, what happened? The ledger postings crashed, it's talking about an invalid cast.

Jeff: Ooops, we should have talked about interfaces in the first place.

When Jeff implemented the change, he didn't think that Bill was dependent upon an Invoice object. When he implemented SuperInvoice, he just created a new type and implemented it within the system. There are several solutions to this problem, those of you familiar with inheritance may see my example as poor as Jeff could have just inherited from Invoice and all should have been fine. However, what Bill and Jeff originally did do was create an IInvoice interface. It gave Bill and Jeff the ability to program their respective parts without worry of the actual implementation of each object, when Jeff came to implement SuperInvoice, he would have implemented the interface and the system at Bill's end would have been none the wiser. It didn't need to be any the wiser. As far as Bill is concerned, it is an invoice, he doesn't need to worry about whether it carries anything not relevant to his system.

Summary

Interfaces are used everywhere throughout the .NET Framework and they are a powerful tool in object orientated programming and design. You may have seen IEnumerable, IDisposable and several others quite frequently while developing other programs. In the case of IDisposable, implementing this interface guarantees you will have a Dispose method on your object (whether you do anything or not[bad practice]).You may see:

using( SqlConnection connection = new SqlConnection( ))
  {
  //Code
  }

The using keyword will take any object that implements IDisposable. When the using statement is complete, it implicitly calls Dispose. If you define your methods to return an IEnumerable<string> it means you can return any collection that implements the IEnumerable interface and contains strings. You can return a list or any other firm object but you guarantee that the object you return will definitely provide certain properties and methods.

In Closing

Well, that is the end of my first article. Hopefully some found it useful and informative. I do now realise the effort that goes into producing something like this and even though I work day in, day out as a developer I realise just how difficult it is to produce a "real world" example to work with. And I apologise for my criticism of other efforts.

History

  • v1.00 - Jan 27th '10 - First version

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