Menu

C# Extension Metotlar: Sözdizimi, IEnumerable, LINQ ve Kurallar

C#'ta extension metotlar nasıl çalışır: ilk parametresinde this olan, statik bir sınıftaki statik bir metot, onu bir örnek metodu gibi çağırmak, string'i, enum'ları ve IEnumerable<T>'yi genişletmek, LINQ'in onlardan nasıl kurulduğu, örnek metotların neden kazandığı, null alıcılar ve ihtiyaç duydukları using yönergesi.

Bu sayfada çalıştırılabilir editörler var - düzenle, çalıştır ve sonucu anında gör.

Bir extension metot, mevcut bir tipe onu değiştirmeden, ondan kalıtım almadan ya da onu sarmalamadan bir metot ekler. Sıradan bir statik metot yazar, ilk parametresini this ile işaretlersiniz ve çağıranlar onu, tipte her zaman varmış gibi nokta sözdizimiyle kullanır:

Çıktı:

Extension methods let yo...
12
short
Extension...

title.Truncate(24) tam olarak StringExtensions.Truncate(title, 24)'e derlenir. Nokta sözdizimi yalnızca bir kolaylıktır: metot hâlâ statiktir, hâlâ StringExtensions içinde yaşar ve yalnızca string'in public üyelerini kullanabilir.

Bildirim Kuralları

  • Metot static olmalı ve static, generic olmayan ve başka bir sınıfın içinde iç içe olmayan bir sınıfta yaşamalıdır. Statik olmayan ya da generic bir sınıf CS1106 verir, Extension method must be defined in a non-generic static class; iç içe olan CS1109 verir, Extension methods must be defined in a top level static class.
  • this yalnızca ilk parametreye yazılır ve o parametrenin tipi genişletilen tiptir. Diğer parametreler normaldir.
  • Sınıf generic olamasa da metodun kendisi generic olabilir (this IEnumerable<T> source).
  • Yalnızca dışarıdaki herhangi bir kodun gördüğünü görür: public (ve aynı assembly içinde internal) üyeler. Private alanlar private kalır.

Gelenek, sınıfı genişlettiği şeye göre adlandırmak (StringExtensions, EnumerableExtensions) ve onları MyApp.Extensions gibi bir namespace'te gruplamaktır.

Interface'leri ve IEnumerable<T>'yi Genişletmek

Bir interface'i genişletmek, metodu onu uygulayan her tipe ekler. Bu yüzden IEnumerable<T>'yi genişletmek, metodu aynı anda dizilere, listelere, küme'lere, dictionary'lerin anahtar koleksiyonlarına ve LINQ sorgu sonuçlarına verir:

Çıktı:

9.5
50
65
f0 f3 f6

EveryNth generic'tir: T alıcıdan çıkarılır, bu yüzden burada string'ler için ve başka her eleman tipi için çalışır. yield return kullandığı için yerleşik LINQ operatörleri gibi tembeldir ve onlarla zincirlenebilir.

LINQ Extension Metotlar Üzerine Kuruludur

Where, Select, OrderBy, Sum, First ve LINQ'in geri kalanı, System.Linq.Enumerable statik sınıfında tanımlanmış IEnumerable<T> üzerindeki extension metotlardır. list.Where(...) derlenmeden önce dosyanın başında using System.Linq; olması gerekmesinin ve hiçbiri bir Where metodu uygulamadığı halde LINQ'in her koleksiyon tipinde çalışmasının nedeni budur:

Çıktı:

72, 88, 95
72, 88, 95

İki satır aynı koddur. Extension sözdizimi, içten dışa okunan iç içe çağrıları adımların gerçekleştiği sırayla okunan bir zincire çevirir; extension metotların var olmasının asıl nedeni budur: C# 3'te LINQ ile birlikte eklendiler. LINQ sayfası operatörleri ele alır.

Namespace İçe Aktarılmalıdır

Bir extension metot yalnızca statik sınıfının namespace'i using ile içe aktarıldığında kapsamdadır. O olmadan çağrı, metot yokmuş gibi başarısız olur:

error CS1061: 'string' does not contain a definition for 'Truncate' and no accessible extension method 'Truncate' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?)

Extension'ların namespace'i için using ekleyin (ya da C# 10'dan itibaren proje için bir kez global using):

Çıktı:

EUR 49.90

Madalyonun öbür yüzü işe yarar: her yerde istemediğiniz bir extension metot, yalnızca bazı dosyaların içe aktardığı bir namespace'te yaşayabilir.

Örnek Metotlar Kazanır

Bir tipin zaten uygulanabilir bir örnek metodu olduğunda derleyici onu kullanır ve extension'ı asla dikkate almaz. Aynı imzaya sahip bir extension, nokta sözdizimi kullanan her çağrı yerinde ölü koddur:

Çıktı:

Invoice (instance method): 120
Invoice (extension): 120 USD
extension: only reachable as a static call

Tek argümanlı extension örnek metoduna kaybetti; iki argümanlı olan kullanıldı, çünkü hiçbir örnek metodu string almıyor. Bu aynı zamanda, extension'ınızın adıyla bir örnek metodu ekleyen bir kütüphane güncellemesinin çağrılarınızı sessizce kütüphanenin sürümüne geçireceği anlamına gelir. Çakışması pek olası olmayan extension adları seçin.

null Üzerinde Çağırmak

Çağrı aslında statik bir çağrı olduğundan, null bir alıcı çağrı yerinde istisna fırlatmaz. Metot ilk argümanı olarak null alır ve bunun ne anlama geldiğine karar verir:

Çıktı:

True
AL
ArgumentNullException: fullName

missing.IsBlank()'in true döndürmesi kullanışlıdır, ama null üzerindeki bir üye çağrısının istisna fırlatmasını bekleyen okuyucuları şaşırtabilir. null'ı yalnızca adı bunu açıkça belli eden metotlarda (IsBlank, OrEmpty) kabul edin; başka yerlerde LINQ'in yaptığı gibi ArgumentNullException fırlatın.

Enum'ları Genişletmek

Enum'ların kendi metotları olamaz, bu da onları doğal bir hedef yapar:

enum OrderStatus { Pending, Paid, Shipped, Delivered, Cancelled }

static class OrderStatusExtensions
{
    public static bool IsFinal(this OrderStatus s) =>
        s == OrderStatus.Delivered || s == OrderStatus.Cancelled;
}

// usage: if (order.Status.IsFinal()) { ... }

C# 14'te Extension Üyeleri

C# 14'e kadar yalnızca metotlar extension olabiliyordu. C# 14, bir alıcı için üyeleri gruplayan ve extension property'lere ve statik üyelere de izin veren extension bloklarını ekledi:

// C# 14 and later
public static class StringExtensions
{
    extension(string s)
    {
        public bool IsBlank => string.IsNullOrWhiteSpace(s);   // extension property
        public string Truncate(int max) => s.Length <= max ? s : s[..max] + "...";
    }
}

Klasik this parametreli extension metotlar geçerliliğini korur ve neredeyse tüm mevcut kod ile kütüphanelerin kullandığı budur.

Ne Zaman Yazılmalı

Extension metotlar, tipin sahibi siz değilken (string, DateTime, framework interface'leri), bir interface'in her uygulamasında aynı yardımcıyı istediğinizde ya da bir zincir iç içe çağrılardan daha iyi okunduğunda uygundur. Sınıfın sahibi sizseniz bunun yerine gerçek bir örnek metodu ekleyin: private durumu kullanabilir ve okuyucuların aradığı yerde görünür. Ve object'i genişletmekten kaçının; bu, metodunuzu programdaki her değerin tamamlama listesine koyar.

Sıkça Sorulan Sorular

C#'ta extension metot nedir?

Başka bir tipin örnek metoduymuş gibi çağrılabilen statik bir metottur. Onu statik bir sınıfta yazar ve ilk parametresinin önüne this koyarsınız: public static bool IsBlank(this string s) => string.IsNullOrWhiteSpace(s);. Bundan sonra name.IsBlank(), string'i değiştirmeden ya da ondan kalıtım almadan her string üzerinde çalışır.

Extension metodum neden bulunamıyor?

Extension metotlar yalnızca namespace'leri içe aktarıldığında görünür. Statik sınıf MyApp.Extensions içindeyse, onu çağıran dosyaya using MyApp.Extensions; ekleyin; aksi halde derleyici tipin o adda bir tanım ve erişilebilir bir extension metot içermediğini söyleyen CS1061'i bildirir. Sınıfın static, generic olmayan ve iç içe olmayan bir sınıf olduğunu da kontrol edin.

Bir extension metot bir örnek metodunu override edebilir mi?

Hayır. Derleyici önce uygulanabilir bir örnek metodu arar ve extension metotları yalnızca hiçbiri yoksa dikkate alır. Bir örnek metoduyla aynı ada ve parametrelere sahip bir extension, örnek sözdizimini kullanan her çağrı yerinde sessizce yok sayılır.

C#'ta null üzerinde extension metot çağrılabilir mi?

Evet. Çağrı, ilk argümanı null olan bir statik metot çağrısına derlenir, bu yüzden çağrının kendisinde NullReferenceException fırlatılmaz. Ne yapılacağına metot karar verir: null'ı geçerli bir girdi olarak ele almak (IsNullOrEmpty tarzı bir yardımcı gibi) ya da LINQ metotlarının yaptığı gibi ArgumentNullException fırlatmak.

C#'ta extension property var mı?

C# 14'ten önce yok. O zamana kadar yalnızca metotlar extension olabilir, bu yüzden property olması istenen şey bir metot olarak yazılır (GetFullName()). C# 14, metotların yanı sıra extension property'leri ve statik üyeleri de bildirebilen extension bloklarını ekledi.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA