In C# Extension methods were introduced with C# 3.0 which make it possible to “extend” existing classes with new methods without access to the source code of those classes. So, in this article, I have explained how we can take benefit of it in C#.

What are Extension Methods?

Extension methods have some differences from regular methods. They can be members of static classes only and their argument list must have one specific parameter that specifies type they are extending. Take a look at the following sample of a very dummy extension method.

Take a look the below example

static class Extensions
{
    public static bool HasMoreThanThreeElements<T>(this IEnumerable<T> enumerable)
    {
        return enumerable.Take(4).Count() > 3;
    }
}

C-sharp-extension-method-min.png

Here is the complete C# Code sample

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
	public static void Main()
	{
		IEnumerable<int> numbers = new List<int> {1,2,3,4,5,6};
        var hasMoreThanThreeElements = numbers.HasMoreThanThreeElements();

	    Console.WriteLine(hasMoreThanThreeElements);
	
	}
}

static class Extensions
{
	public static bool HasMoreThanThreeElements<T>(this IEnumerable<T> enumerable)
	{
		return enumerable.Count() > 3;
	}
}

Output:

True

Another Example Of Extension Method

To get more realistic I will show here some real extension methods.

public static class StringExtensions
{
    public static string Nl2Br(this string s)
    {
        return s.Replace("\r\n", "<br />")
                .Replace("\n", "<br />");
    }
 
    public static string Repeat(this string instr, int n)
    {
        if (string.IsNullOrEmpty(instr))
        {
            return instr;
        }
 
        return new StringBuilder(instr.Length * n)
                        .Insert(0, instr, n)
                        .ToString();
    }
 
    public static string MD5(this string s)
    {
        var provider = new MD5CryptoServiceProvider();
        var bytes = Encoding.UTF8.GetBytes(s);
        var builder = new StringBuilder();
 
        bytes = provider.ComputeHash(bytes);
 
        foreach (byte b in bytes)
        {
            builder.Append(b.ToString("x2").ToLower());
        }
 
        return builder.ToString();
    }
}

Linq in C# has many extension methods, let's take a look at an example of Extension methods in C# Linq.

Here is the example of Linq function with Extension Method

var invoices = _context.Invoices.Where(i => i.Customer.Id == 1)
                                .OrderByDescending(i => i.Date)
                                .Select(i => new { Date = i.Date, Total = i.Total })
                                .ToList();

All it does is selecting invoices for given customer, ordering these by invoice date in descending order and returning list of dates and totals for invoices. Notice that Where(), OrderByDescending(), Select() and ToList() are all extension methods.

Now, the same query without extension methods would be like

var query = Enumerable.Where(_context.Invoices, i => i.Customer.Id == 1);
query = Enumerable.OrderByDescending(query, i => i.Date);
var query2 = Enumerable.Select(query, i => new { Date = i.Date, Total = i.Total });
var invoices = Enumerable.ToList(query2);

If we change the above C# query to the nested version of it, it will become more ugly.

var invoices = Enumerable.ToList(
                    Enumerable.Select(
                        Enumerable.OrderByDescending(
                            Enumerable.Where(_context.Invoices, i => i.Customer.Id == 1),
                            i => i.Date), 
                        i => new { Date = i.Date, Total = i.Total }
                    )
                );

This makes it both difficult to read and understand the query.

So, you can see the first query with Linq and Extension method in it, makes life easier for Developer, also it looks easy to read and understand, that's where Extension methods are useful.

Usage of Extension Method

Extension methods cannot access protected and private members of the class. If they are defined in separate assembly then they don’t have access also to internal members of the class.

  • use extension methods only for extending the public surface of class, don’t make internals available to extension methods
  • if access to protected members is needed then better use inheritance
  • don’t create extension methods you probably need to call only once in application code
  • if your extension methods are general enough to use them in multiple projects then consider creating a separate library for them
  • keep extension methods at some upper namespace in the hierarchy because otherwise, they are hard to find for other developers

Finally, before adding a new extension method it is a good idea to stop for a moment and think if it should be extension method or something else.

A good extension method should:

  • Apply to any possible instance of the type it extends.
  • Simplify logic and improve readability/maintainability.
  • Apply to the most specific type or interface applicable.
  • Be isolated in a namespace so that it does not pollute IntelliSense.

Final Thoughts on Extension Methods

  • Extension methods are methods that are displayed as a members of class instance by development tools.
  • Extension methods are internally static methods of some static class.
  • Methods are decorated with ExtensionAttribute to tell development tools that these methods use keywords “this” with their first argument.
  • In all other means extension methods are like all other methods. Adding new extension method is the matter of code design. Performance-wise they are equal to all other static methods that make same work.