Trusted answers to developer questions
Trusted Answers to Developer Questions

Related Tags

c#

What are extension functions in C#?

Rafael Câmara

Overview

Extensions methods are methods that we can add to our code or third-party library that allow us to extend or add functionality.

Let's see a simple coding example to show this concept in action.

Code example

Let's assume we have a third-party library whose only purpose is to log messages (in our case, to the console). To keep it simple, we have already written the log class. Let's see the code below:

    /*
     * Let's assume this is given in a third-party library
     */
    public class Logger
    {
        public void Log(string message)
        {
            Console.WriteLine($"Logged message: {message}");
        }
    }

To log a particular message, instantiate the Logger class and call the log method.

But what if we want to give special treatment to error messages and print an error. We don't have access to that source code, so we can't change the Logger library.

C# provides us with a way to extend the functionality of the Logger library without modifying the original source code.

Add the following code to the above widget to add the LogError method.

public static class LoggerExtensions
    {
        public static void LogError(this Logger logger, string errorType, string message)
        {
            Console.WriteLine($"Error {errorType}: {message}");
        }
    }

Code explanation

Line 1: We create a static class that contains all the extensions we can create for the Logger library.

Line 3: We create a static method, which represents the additional method that we add to the library. Here we have a couple of things to notice:

    • The first parameter has to be the class to be extended. To do so, we must first use the keyword and then insert the class to be extended like a traditional parameter.
    • After the first parameter, we must add the remaining wanted parameters like a regular method. As you can see from the method, we have added two parameters: errorType and message.

The following code shows the log obtained:

using System;
namespace ExtensionMethods
{
    internal class Program
    {
        public static void Main(string[] args)
        {
            Logger logger = new Logger();
            logger.LogError("NullException", message: "object reference was null");
        }
    }
}
public static class LoggerExtensions
{
    public static void LogError(this Logger, string errorType, string messege)
    {
        Console.WriteLine($"Error {errorType}: {message}");
    }
}
Log obtained by executing the Log method inside the Logger Class

In this case, we extend the functionality of a particular class, but we can also abstract this even more and consider extending functionality to interfaces. This means that every class that implements that interface will also be able to use the extended method.

Let's look at this in practice with our Logger class. Let's modify the following code:

 public interface ILogger
    {
        void Log(string message);
    }

public static class LoggerExtensions
    {
        public static void LogError(this ILogger logger, string errorType, string message)
        {
            Console.WriteLine($"Error {errorType}: {message}");
        }
    }


    /*
     * Let's assume this is given in a third party library
     */

    public class Logger : ILogger
    {
        public void Log(string message)
        {
            Console.WriteLine($"Logged message: {message}");
        }
    }

    public class AnotherLogger : ILogger
    {
        public void Log(string message)
        {
            Console.WriteLine($"Logged message in another logger: {message}");
        }
    }

Code explanation

Line 1: We create the ILogger interface that contains the important log method.

Line 19: We create the Logger class.

Line 27: We create the AnotherLogger class implement the created interface.

Notice the static class we created for extensions and compare it with the same class from the previous example. Notice the difference? In our first example, we extend the Logger class, but now we extend the interface ILogger, and as a result, every class that implements the interface will access the extension method.

If we now instantiate Logger and AnotherLogger objects, we can see that the extension method is available to us.

The following code shows a possible execution output:

using System;
 public interface ILogger
    {
        void Log(string message);
    }

public static class LoggerExtensions
    {
        public static void LogError(this ILogger logger, string errorType, string message)
        {
            Console.WriteLine($"Error {errorType}: {message}");
        }
    }


    /*
     * Let's assume this is given in a third party-library
     */

    public class Logger : ILogger
    {
        public void Log(string message)
        {
            Console.WriteLine($"Logged message: {message}");
        }
    }

    public class AnotherLogger : ILogger
    {
        public void Log(string message)
        {
            Console.WriteLine($"Logged message in another logger: {message}");
        }
    }
namespace ExtensionMethods
{
    internal class Program
    {
        public static void Main(string[] args)
        {
            Logger logger = new Logger();
            logger.LogError("NullException",message:  "Object reference was null");
            AnotherLogger anotherLogger = new AnotherLogger();
            anotherLogger.LogError("DivisionByZero", message: "can't divide by Zero");
        }
    }
}

We can also have extension methods in enums. The rationale behind it is the same as with interface, so we won't go into much detail (also because it's not as common to do extension methods in enums).

Before moving on, if you want to look at the source code, click here.

When to consider using extension methods

It's advised to use the extension methods in the following situations:

  • When we add/extend functionality to a third-party library, we don't have direct access to the code and, therefore, can't change it.
  • If we do extension methods in our code and not in a third-party library, in that case, we have the benefit of adding functionality on top of the existing one, which helps us introduce bugs in the existing code, and make testing this new functionality much easier.

When not to use extension methods

It's recommended not to use extension methods in the following situations:

  • If we want to extend the base types existent in the language (ex. strings), unless we do this operation multiple times and in multiple places, and this saves time.
  • It is not guaranteed that the extension method code will be executed, as methods directly on the type take precedence (methods with the same signature). We should consider this since it might cause nasty, unwanted behavior.
  • If we need access to private or protected members, we can't access them from the extension methods.

Stuff to consider

We have covered a lot of ground in this article.

Here are the main takeaways from this:

  1. Extension methods are additional methods that were initially not included with the code/library provided.
  2. The first parameter of the extension method must be of the type for which the extension method is applicable, preceded by this keyword.
  3. Extension methods can be used anywhere in our application if we include the namespace of the extension method.
  4. Extension methods cannot be used to override existing methods. As we have seen, the instance methods have higher precedence.

RELATED TAGS

c#
RELATED COURSES

View all Courses

Keep Exploring