C# tutorials > Core C# Fundamentals > Object-Oriented Programming (OOP) > What are extension methods?

What are extension methods?

Extension methods enable you to add new methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type. They are a special kind of static method that is called as if they were instance methods on the extended type. This allows you to 'inject' functionality into classes or interfaces you don't own, making your code more readable and maintainable. They are defined in a static class, and the first parameter specifies the type that the method operates on, preceded by the this keyword.

Basic Syntax and Example

This code defines an extension method called Capitalize for the string type. Notice that the method is defined within a static class called StringExtensions and is also a static method. The first parameter of the Capitalize method is this string str. The this keyword specifies that this is an extension method and that it extends the string type. The method takes a string as input and returns a new string with the first letter capitalized. The Main method demonstrates how to use the extension method. You call Capitalize as if it were an instance method of the string class.

using System;

public static class StringExtensions
{
    public static string Capitalize(this string str)
    {
        if (string.IsNullOrEmpty(str))
        {
            return str;
        }
        return char.ToUpper(str[0]) + str.Substring(1);
    }
}

public class Example
{
    public static void Main(string[] args)
    {
        string myString = "hello world";
        string capitalizedString = myString.Capitalize();
        Console.WriteLine(capitalizedString); // Output: Hello world
    }
}

Concepts Behind the Snippet

The core concept behind extension methods is to provide a way to extend the functionality of existing types without modifying them directly. This adheres to the Open/Closed Principle from the SOLID principles, which states that software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.

Extension methods are resolved at compile time. The compiler searches for extension methods in scope based on namespaces that are imported with using directives. The correct extension method is selected based on the type of the object and the name and parameters of the method call.

Real-Life Use Case Section

A common real-life use case is adding pagination to IEnumerable collections. The code above defines an extension method called Page that takes an IEnumerable, a page number, and a page size as input, and returns a new IEnumerable containing only the items for the specified page. This functionality is useful when displaying large datasets in a user interface, where it's often necessary to break the data into smaller, more manageable pages.

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

public static class EnumerableExtensions
{
    public static IEnumerable<T> Page<T>(this IEnumerable<T> source, int page, int pageSize)
    {
        if (pageSize <= 0)
        {
            throw new ArgumentOutOfRangeException("pageSize", "Page size must be greater than zero.");
        }

        if (page <= 0)
        {
            throw new ArgumentOutOfRangeException("page", "Page number must be greater than zero.");
        }

        return source.Skip((page - 1) * pageSize).Take(pageSize);
    }
}

public class Example
{
    public static void Main(string[] args)
    {
        List<int> numbers = Enumerable.Range(1, 50).ToList();

        // Get the first page of 10 items
        IEnumerable<int> firstPage = numbers.Page(1, 10);

        foreach (int number in firstPage)
        {
            Console.WriteLine(number);
        }
        //Output 1 to 10
    }
}

Best Practices

  • Keep extension methods in dedicated, well-named static classes: This improves code organization and readability. For example, place all extension methods for strings in a class named StringExtensions.
  • Avoid naming conflicts: Choose names for your extension methods that are unlikely to conflict with existing or future methods of the extended type.
  • Don't overuse extension methods: Only use them when they logically extend the functionality of a type. If the functionality is unrelated to the type, consider using a regular static method instead.
  • Consider Null Checks: Include null checks to avoid exceptions when the extended object is null.

Interview Tip

When discussing extension methods in an interview, be prepared to explain their purpose, syntax, and benefits. Also, be ready to discuss scenarios where extension methods are appropriate and where they are not. Demonstrate your understanding of the Open/Closed Principle and how extension methods help to adhere to it.

A good interview answer will also cover performance considerations and potential drawbacks, such as the possibility of naming conflicts.

When to Use Them

Use extension methods when you want to add functionality to a type that you don't own or cannot modify. This is especially useful when working with third-party libraries or framework types. Extension methods are also a good way to add utility methods to your own types without cluttering the original class definition.

Memory Footprint

Extension methods themselves don't introduce a significant memory footprint. They are static methods, and their code resides in the method table of the static class where they are defined. The impact on memory comes from the data structures that are created and used within the extension method itself. For example, the Capitalize method creates a new string object, which consumes memory. The Page extension method creates an iterator which can have a small footprint.

Alternatives

  • Inheritance: If you control the source code of the class you want to extend, you could use inheritance to create a derived class with the new functionality. However, this is not always possible or desirable, especially when extending sealed classes.
  • Helper Classes: You can create a helper class with static methods that operate on instances of the original type. However, this approach can make the code less readable, as you have to call the helper methods explicitly, rather than calling the methods as if they were instance methods.

Pros

  • Extends existing types without modification: Add new functionality without altering original code.
  • Improved readability: Methods called as if they were instance methods.
  • Open/Closed Principle: Allows extension of types without modifying them.
  • Clean code: Reduces code duplication by providing reusable functionality.

Cons

  • Naming conflicts: Potential for conflicts with existing or future methods.
  • Discoverability: Can be harder to discover than instance methods. Requires knowing the extension method exists in the right namespace.
  • Overuse: Can lead to code that is less maintainable if used inappropriately.

FAQ

  • Can I create extension methods for interfaces?

    Yes, you can create extension methods for interfaces. This allows you to provide default implementations for interface methods, which can be useful when adding new methods to an existing interface without breaking existing implementations.

  • Can I extend sealed classes using extension methods?

    Yes, extension methods are a great way to add functionality to sealed classes because you cannot inherit from them.

  • What happens if an extension method has the same signature as an existing method of the type?

    If an extension method has the same signature as an existing method (instance method) of the type, the instance method will always take precedence. The extension method will only be called if there is no matching instance method.