Click here to Skip to main content
15,881,882 members
Articles / All Topics

How Interfaces, Generics and Extension Methods Can Make Code Cleaner

Rate me:
Please Sign up or sign in to vote.
4.58/5 (14 votes)
4 Nov 2014CPOL2 min read 21.9K   14   7
An example of how interfaces, generics and extension methods can drastically reduce code replication

From personal experience, one of my biggest gripes when working with code is code duplication.  Code duplication makes code appear bloated, harder to read, harder to test and can cause replication of not just the code, but of bugs contained within.

Thankfully, we have three very useful features that individually, and collectively can drastically reduce the amount of code we need to write, and subsequently test.

Let's take a simple list:

C#
List<object> objects = new List<object>
{ "Hello", 1, "World", 3.4m, DateTime.Now, true};

If we want to get all of the string objects out of the list, we could do something like:

C#
List<string> output = new List<string>();

foreach (object o in objects)
{
   if(o.GetType() == typeof(string))
   {
     output.Add((string)o);
   }
}

And then maybe, if we needed to extract the integers from the same list, we’d do:

C#
List<int> output2 = new List<int>();

foreach (object o in objects)
{
   if(o.GetType() == typeof(int))
   {
     output.Add((int)o);
   }
}

But already we are almost replicating the code. This is where generics comes in handy. We can convert the same 2 methods into a single method as follows:

C#
public List<T> GetAllOfType<T>(List<object> o)
{
 List<T> output = new List<T>();

 foreach (object item in o)
 {
    if (item.GetType() == typeof(T))
    {
      output.Add((T)(object)item);
    }
  }
  return output;
}

And then call the method with:

C#
List<string> strings = GetAllOfType<string>(objects);
List<int> ints = GetAllOfType<int>(objects);

Note: It’s better to cast to object before casting to T as the compiler always knows the route from object to T, but can sometimes protest casting directly from one object to T without the intermediary step. In the above example, it’s not essential.

Now we have the method, it would make sense to make the method available from any class rather than just in the class we’re using. This allows maximum reuse, again meaning we’ll not need to replicate this. To do this, we create an extension method by creating a new static class, and placing the method in there, making sure the method is also static and adding the ‘this’ keyword to the List parameter:

C#
public static List<T> GetAllOfType<T>(this List<object> o)
{
  List<T> output = new List<T>();

  foreach(object item in o)
  {
    if(item.GetType() == typeof(T))
    {
      output.Add((T)(object)item);
    }
  }
  return output;
}

As you will, we can now see this method appear in our intellisense:
ext1
Notice we now call the method on the original list rather than pass the collection as the argument.

So now, we have an extension method available to retrieve all objects of a certain type from a list.

However, we can still improve this through the use of interfaces. Suppose we want to be able to retrieve all objects of a type from an array for example. Rather than creating a separate extension method for an array, we can remove the reference to the list and replace it with a reference to the IEnumerable interface, which is implemented both by a List and an array, along with many other collections:

C#
public static IEnumerable<T> GetAllOfType<T>(this IEnumerable<object> o)
{
   List<T> output = new List<T>();

   foreach(object item in o)
   {
        if(item.GetType() == typeof(T))
        {
            output.Add((T)(object)item);
        }
    }
    return output;
}

We can now user the same extension method for lists and arrays as follows:

C#
List<object> objectList = new List<object>
{ "Hello", 1, "World", 3.4m, DateTime.Now, true};
object[] objectArray = new object[] { "Hello", 1, "World", 3.4m, DateTime.Now, true };


IEnumerable<string> strings = objectList.GetAllOfType<string>();
IEnumerable<int> ints = objectArray.GetAllOfType<int>();

Clearly, this is a very simplistic example, but as you can see, mixing interfaces, generics and extension methods can create very concise flexible code. The above example doesn’t need to be taken much further to become very useful when working with abstract classes.

License

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


Written By
Software Developer (Senior)
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionTesting Pin
oliversweb7-Nov-14 22:15
oliversweb7-Nov-14 22:15 
GeneralMy vote of 1 Pin
Phil Deg5-Nov-14 11:03
Phil Deg5-Nov-14 11:03 
QuestionThis is already part of the .Net Framework Pin
Phil Deg5-Nov-14 11:03
Phil Deg5-Nov-14 11:03 
AnswerRe: This is already part of the .Net Framework Pin
Wastedtalent5-Nov-14 20:03
professionalWastedtalent5-Nov-14 20:03 
QuestionWhat's what? Pin
Adrian Wadey5-Nov-14 2:14
professionalAdrian Wadey5-Nov-14 2:14 
AnswerRe: What's what? Pin
Earl L Wilkerson Jr5-Nov-14 8:34
Earl L Wilkerson Jr5-Nov-14 8:34 
QuestionStill room for improvement Pin
Yakigato Niji4-Nov-14 10:51
Yakigato Niji4-Nov-14 10:51 

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.