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.
