Extension-metoder
Extension-metoder låter dig lägga till metoder på en befintlig typ — utan att ändra typen och utan arv. Det ser ut som om metoden hör till typen, men den definieras separat.
När du läst detta ska du kunna
- Skriva en extension-metod
- Aktivera den med rätt
using - Förklara varför
thisär det magiska nyckelordet
Syntax
// Statisk klass med statisk metod// Det första argumentet har nyckelordet thispublic static class StringExtensions{ public static bool IsEmail(this string value) => value.Contains('@') && value.Contains('.');}Användning
string email = "anna@example.com";Console.WriteLine(email.IsEmail()); // TrueConsole.WriteLine("inte-epost".IsEmail()); // FalseDet ser ut som en vanlig instansmetod — men den är faktiskt en statisk metod i en separat klass.
Regler
- Klassen måste vara
static - Metoden måste vara
static - Första parametern:
this TypDuUtökar name - Klassen måste vara i ett tillgängligt namespace (
using)
Utöka inbyggda typer
Du kan lägga till metoder på typer du inte äger — string, int, List<T>:
public static class IntExtensions{ public static bool IsEven(this int n) => n % 2 == 0; public static bool IsOdd(this int n) => n % 2 != 0;
public static string Repeat(this string s, int times) => string.Concat(Enumerable.Repeat(s, times));}Console.WriteLine(4.IsEven()); // TrueConsole.WriteLine(7.IsOdd()); // TrueConsole.WriteLine("ha".Repeat(3)); // hahahaExtension-metoder på List<T>
public static class ListExtensions{ public static void PrintAll<T>(this IEnumerable<T> items, string label = "") { if (label != "") Console.WriteLine($"{label}:"); foreach (var item in items) Console.WriteLine($" {item}"); }
public static T RandomItem<T>(this IList<T> items) { var rng = Random.Shared; return items[rng.Next(items.Count)]; }}var names = new List<string> { "Anna", "Björn", "Clara" };names.PrintAll("Deltagare");
Console.WriteLine($"Slumpmässig: {names.RandomItem()}");Output
Participants: Anna Björn ClaraRandom: BjörnLINQ är extension-metoder
Hela LINQ-biblioteket är byggt på extension-metoder på IEnumerable<T>:
// Where, Select, OrderBy är alla extension-metodervar sorted = names.Where(n => n.Length > 3) .OrderBy(n => n) .ToList();Namespace och using
Extension-metoderna aktiveras när du lägger till rätt using:
using MyApp.Extensions; // aktiverar alla extension-metoder i det namespacet
// Nu fungerar:"test".IsEmail();Utan using ser typen inte metoderna.
Det nya extension-blocket
Det gamla sättet med static class + this fungerar fortfarande, men det finns nu en modernare syntax med extension-blocket. Det löser den gamla begränsningen — du kan lägga till properties, indexerare och statiska members, inte bara metoder:
// Gammalt sätt — bara metoderpublic static class StringExtensions{ public static bool IsEmail(this string s) => s.Contains('@') && s.Contains('.');}
// Nytt sätt — metoder, properties och indexerare i ett blockpublic static class StringExtensions{ extension (string s) { public bool IsEmail => s.Contains('@') && s.Contains('.'); // property! public string Reversed => new(s.Reverse().ToArray()); // property! public string Repeat(int times) // metod => string.Concat(Enumerable.Repeat(s, times)); }}"anna@exempel.se".IsEmail // True — property-syntax, inte metodanrop"hej".Reversed // "jeh""ha".Repeat(3) // "hahaha"Se Extension-properties och Extension-indexerare för fler exempel på det nya blocket.
Begränsningar (gamla sättet)
- Kan inte komma åt privata fält — bara publika/interna members
- Instansmetoder på typen prioriteras — din extension döljs om typen själv har en metod med samma namn och signatur
- Kan inte lägga till properties eller indexerare — använd det nya
extension-blocket för det
TL;DR
// 1. Statisk klasspublic static class Extensions{ // 2. Statisk metod med this på första parametern public static bool StartsWithVowel(this string s) => "aeiouåäö".Contains(char.ToLower(s[0]));}
// 3. Används som vanlig metod"Anna".StartsWithVowel(); // True"Björn".StartsWithVowel(); // FalseExtension-metoder är kärnan i LINQ och en av C#:s kraftfullaste konventioner.