C# Extension Methods

Extension methods let you add new methods to an existing type without modifying its source code or creating a subclass. They appear and behave exactly like built-in methods on the type — but live in a separate static class that you define.

Why Extension Methods?

┌──────────────────────────────────────────────────────────────┐
│  You want to add a method to the string class.               │
│                                                              │
│  Problem: string is sealed — you cannot inherit it.          │
│  Problem: You don't have access to the string source code.   │
│                                                              │
│  Solution: Extension methods — add the method externally,    │
│  but call it as if it belongs to string.                     │
│                                                              │
│  "Hello World".WordCount()   ← looks like a string method    │
│                                  defined by you externally   │
└──────────────────────────────────────────────────────────────┘

Creating an Extension Method

Extension methods must be:

  • In a static class
  • Themselves static
  • First parameter prefixed with this followed by the type being extended
// Static class to hold extension methods:
public static class StringExtensions
{
    // 'this string s' means: extend the string type
    public static int WordCount(this string s)
    {
        if (string.IsNullOrWhiteSpace(s)) return 0;
        return s.Trim().Split(' ').Length;
    }

    public static string Reverse(this string s)
    {
        char[] chars = s.ToCharArray();
        Array.Reverse(chars);
        return new string(chars);
    }

    public static bool IsPalindrome(this string s)
    {
        string clean = s.ToLower().Replace(" ", "");
        return clean == new string(clean.ToCharArray().Reverse().ToArray());
    }
}

Calling Extension Methods

string sentence = "Hello World from C#";

Console.WriteLine(sentence.WordCount());    // 4
Console.WriteLine("abcde".Reverse());       // edcba
Console.WriteLine("racecar".IsPalindrome()); // True
Console.WriteLine("hello".IsPalindrome());   // False

Extension Method Anatomy

┌──────────────────────────────────────────────────────────────┐
│                                                              │
│  public static int WordCount(this string s)                  │
│  │      │      │       │      │      │                       │
│  │      │      │       │      │      └── parameter name      │
│  │      │      │       │      └── type being extended        │
│  │      │      │       └── 'this' keyword = extension marker │
│  │      │      └── return type                               │
│  │      └── must be static                                   │
│  └── must be public (or accessible)                          │
│                                                              │
└──────────────────────────────────────────────────────────────┘

Extending int and Other Value Types

public static class IntExtensions
{
    public static bool IsEven(this int n)
    {
        return n % 2 == 0;
    }

    public static bool IsPositive(this int n)
    {
        return n > 0;
    }

    public static int Clamp(this int n, int min, int max)
    {
        if (n < min) return min;
        if (n > max) return max;
        return n;
    }
}

class Program
{
    static void Main()
    {
        Console.WriteLine(8.IsEven());        // True
        Console.WriteLine(7.IsEven());        // False
        Console.WriteLine((-5).IsPositive()); // False

        int score = 110;
        Console.WriteLine(score.Clamp(0, 100));  // 100
        // clamped to max of 100
    }
}

Extending Collections

public static class ListExtensions
{
    public static void PrintAll<T>(this List<T> list)
    {
        foreach (var item in list)
            Console.WriteLine(item);
    }

    public static T SecondOrDefault<T>(this List<T> list)
    {
        return list.Count >= 2 ? list[1] : default(T);
    }
}

class Program
{
    static void Main()
    {
        List<string> names = new List<string>() { "Alice", "Bob", "Carol" };

        names.PrintAll();
        // Alice
        // Bob
        // Carol

        Console.WriteLine(names.SecondOrDefault());  // Bob
    }
}

LINQ Uses Extension Methods

All of LINQ's methods — Where(), Select(), OrderBy() — are extension methods defined in System.Linq on IEnumerable<T>. This is exactly why you can call them on any list or array.

┌──────────────────────────────────────────────────────────────┐
│  names.Where(n => n.Length > 3)                              │
│      ↑                                                       │
│  Where() is an extension method on IEnumerable<T>            │
│  Defined in System.Linq namespace                            │
│  Available on List, Array, HashSet, and any IEnumerable      │
└──────────────────────────────────────────────────────────────┘

Extension Methods vs Helper Classes

┌──────────────────────────────┬───────────────────────────────┐
│ Helper Class (old style)     │ Extension Method (modern)     │
├──────────────────────────────┼───────────────────────────────┤
│ StringHelper.WordCount(s)    │ s.WordCount()                 │
├──────────────────────────────┼───────────────────────────────┤
│ Must pass object explicitly  │ Called on the object directly │
├──────────────────────────────┼───────────────────────────────┤
│ Breaks reading flow          │ Reads naturally               │
├──────────────────────────────┼───────────────────────────────┤
│ Does not chain               │ Chains fluently               │
│                              │s.Trim().WordCount().ToString()│
└──────────────────────────────┴───────────────────────────────┘

Chaining Extension Methods

public static class StringExtensions
{
    public static string RemoveSpaces(this string s)  { return s.Replace(" ", ""); }
    public static string ToTitleCase(this string s)
    {
        if (string.IsNullOrEmpty(s)) return s;
        return char.ToUpper(s[0]) + s.Substring(1).ToLower();
    }
}

string input = "  hello world  ";

string result = input
    .Trim()           // built-in
    .ToTitleCase()    // extension
    .RemoveSpaces();  // extension

Console.WriteLine(result);  // HelloWorld

Rules and Limitations

┌────────────────────────────────────────────────────────────┐
│  Rules:                                                    │
│  ✅ Must be in a static class                              │
│  ✅ Method must be static                                  │
│  ✅ First param must have 'this'                           │
│  ✅ Can extend any type (class, struct, interface)         │
│  ✅ Only accessible after importing the namespace          │
│                                                            │
│  Limitations:                                              │
│  ❌ Cannot access private members of the extended type     │
│  ❌ Instance methods of the type take priority             │
│  ❌ Cannot override existing methods                       │
└────────────────────────────────────────────────────────────┘

Quick Summary

┌──────────────────────────────────────────────────────────────┐
│  static class MyExtensions                                   │
│  {                                                           │
│      public static ReturnType MethodName(this Type obj, ...) │
│      { ... }                                                 │
│  }                                                           │
│                                                              │
│  Usage: obj.MethodName(...)                                  │
│                                                              │
│  Key benefit:                                                │
│  Add methods to types you don't own (string, int, List)      │
│  without inheritance or modifying source code                │
└──────────────────────────────────────────────────────────────┘

Extension methods keep your code clean and readable. They let you add domain-specific behaviour to any type while preserving the fluent, chained style that makes C# enjoyable to write. Every time you use LINQ, you are using extension methods — now you can build your own.

Leave a Comment

Your email address will not be published. Required fields are marked *