How Interfaces, Generics and Extension Methods Can Make Code Cleaner

Search for a command to run...

No comments yet. Be the first to comment.
A series of articles imported from my previous blog hosted at https://www.talkingitthrough.co.uk.
What is swagger and why should I use it? Swagger is a specification of rules/notation used to define how an API should be documented. As of Swagger version 2.0, it is now been renamed to the OpenApi specification. This reflects that the specification...
Introduction Semantic Kernel is an open-source framework by Microsoft that integrates machine learning and natural language processing to build AI applications. It offers tools for tasks like language understanding, text generation, and semantic sear...

Introduction In the earlier articles in my PDF Splitter series, we have relied on the inbuild .NET libraries to handle working with PDF files in MAUI, but these only support opening and displaying of PDF files. Now that we are looking to save our new...

Introduction In the previous article, we created a PDF model and service to allow us to work with and track PDF pages. The next step is to build the UI to allow us to interact with the service. To do this we will create a single 'view' and a 'view mo...

Introduction For the fourth article in my PDF Splitter series, we will start working with PDF files in .NET MAUI. Helpfully, MAUI contains a lot of useful PDF tools for reading PDF files out of the box, so we do not need to use any additional librari...

Introduction In this article, I'm going to introduce basic navigation into my .NET MAUI PDF Splitter application. If you're following my PDF Splitter Application series, you will have a simple application based on the out-the-box .NET template with a...

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 contain 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.
Lets take a simple list:
List objects = new List { "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:
List output = new List();
foreach (object o in objects)
{
if(o.GetType() == typeof(string))
{
output.Add((string)o);
}
}
And then maybe if we needed to do extract the integers from the same list we’d do:
List output2 = new List();
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:
public List GetAllOfType(List o)
{
List output = new List();
foreach (object item in o)
{
if (item.GetType() == typeof(T))
{
output.Add((T)(object)item);
}
}
return output;
}
And then call the method with:
List strings = GetAllOfType(objects);
List ints = GetAllOfType(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:
public static List GetAllOfType(this List o)
{
List output = new List();
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:

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:
public static IEnumerable GetAllOfType(this IEnumerable o)
{
List output = new List();
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:
List objectList = new List { "Hello", 1, "World", 3.4m, DateTime.Now, true};
object\[\] objectArray = new object\[\] { "Hello", 1, "World", 3.4m, DateTime.Now, true };
IEnumerable strings = objectList.GetAllOfType();
IEnumerable ints = objectArray.GetAllOfType();
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.
The post How Interfaces, Generics and Extension Methods Can Make Code Cleaner appeared first on Talking I.T. Through.