> ## Content Index
> Fetch the complete content index at: https://hasan-aytac.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# C# 2026: Extension Members ile Daha Temiz API Tasarımı
- URL: https://hasan-aytac.com/csharp-2026-extension-members/
- Published: 2026-10-13T08:58:19.000Z
- Updated: 2026-10-13T08:58:19.000Z
- Description: C# 14 extension bloklarıyla uzantı özellikleri ve statik uzantılar yazın. Derlenip çalıştırılmış .NET 10 örnekleriyle API tasarımını sadeleştirin.
- Author: Hasan Aytaç
- Tags: csharp, dotnet, programming, C# 2026, #editorial-csharp-2026

> **Sürüm notu:** “C# 2026” resmî bir dil sürümü adı değil, bu rehberin çalışma dönemidir. Örnekler kararlı **.NET 10 ve C# 14** içindir; önizleme özellikleri kullanılmaz.

Bir müşteri kaydının görünen adını hesaplamak için küçük bir yardımcı metot yazmak kolaydır. Asıl mesele, bu yardımcıların sayısı arttığında çağıran kodun anlaşılır kalmasıdır. `CustomerHelpers.GetDisplayName(customer)` yerine `customer.DisplayName` okumak, doğru bağlamda daha doğal olabilir.

C# 14’ün **extension members** özelliği tam olarak bu noktada işe yarar: mevcut bir tipe uzantı metotlarının yanında uzantı özellikleri de ekleyebiliriz. Üstelik yalnızca nesneyi değil, tipin kendisini hedefleyen statik uzantılar da tanımlayabiliriz.

Bu yazıda küçük bir müşteri modeli üzerinden ilerleyelim. Amaç mümkün olan en kısa kodu yazmak değil; neyin gerçek bir üye, neyin uzantı olduğunu bilerek okunaklı bir API oluşturmaktır.

## 1\. Ortamı doğru ayarlayın

.NET 10 hedefleyen bir konsol projesi oluşturun:

```bash
dotnet new console -n ExtensionDemo -f net10.0
cd ExtensionDemo

```

`net10.0` için varsayılan dil sürümü C# 14’tür. Örneklerle aynı ayarı açıkça belirtmek isterseniz proje dosyanız şöyle olabilir:

```xml
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net10.0</TargetFramework>
    <LangVersion>14.0</LangVersion>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
</Project>

```

`LangVersion=latest` kullanmak yerine hedef çerçevenin varsayılanına veya belirli bir sürüme bağlı kalın. Böylece geliştirici bilgisayarı ile CI ortamında farklı dil özelliklerinin devreye girmesini önlersiniz.

## 2\. Klasik extension metodu hâlâ geçerli

Önce modelimiz:

```csharp
namespace CSharp2026.ExtensionMembers;

public sealed record Customer(string FirstName, string LastName);

```

C# 14 öncesinde bu modele bir ad biçimlendirme yardımcısı eklemek için ilk parametresinde `this` bulunan statik bir metot kullanırdık:

```csharp
namespace CSharp2026.ExtensionMembers;

public static class LegacyCustomerExtensions
{
    public static string GetDisplayName(this Customer customer)
    {
        ArgumentNullException.ThrowIfNull(customer);
        return $"{customer.FirstName.Trim()} {customer.LastName.Trim()}".Trim();
    }
}

```

Bu kod hâlâ desteklenir. Mevcut extension metotlarınızı sırf yeni sözdizimi geldi diye topluca değiştirmeniz gerekmez. Çağıran taraf `customer.GetDisplayName()` yazmaya devam edebilir.

Ancak hesaplanan değeri bir özellik olarak sunmak istiyorsanız, yeni extension blokları daha uygun bir ifade biçimi sağlar.

## 3\. Bir extension bloğunda birden fazla üye

Aşağıdaki kodu ayrı bir `CustomerExtensions.cs` dosyasına koyun:

```csharp
namespace CSharp2026.ExtensionMembers;

public static class CustomerExtensions
{
    extension(Customer customer)
    {
        public string DisplayName
        {
            get
            {
                ArgumentNullException.ThrowIfNull(customer);
                return $"{customer.FirstName.Trim()} {customer.LastName.Trim()}".Trim();
            }
        }

        public string ToGreeting() => $"Merhaba, {customer.DisplayName}!";
    }

    extension(Customer)
    {
        public static Customer CreateGuest() => new("Misafir", string.Empty);
    }
}

```

İlk bloktaki `customer`, uzantının uygulandığı nesnedir. `DisplayName` özellik gibi görünür; `ToGreeting()` ise metot gibi çağrılır. İkinci blokta nesne adı bulunmaz: `extension(Customer)` doğrudan tipe yönelik statik üyeleri tanımlar.

Kullanımı:

```csharp
using CSharp2026.ExtensionMembers;

var customer = new Customer(" Ada ", " Lovelace ");
Console.WriteLine(customer.DisplayName);
Console.WriteLine(customer.ToGreeting());
Console.WriteLine(Customer.CreateGuest().DisplayName);

```

Beklenen çıktı:

```text
Ada Lovelace
Merhaba, Ada Lovelace!
Misafir

```

`CreateGuest()` mevcut `Customer` sınıfının kaynak kodunda tanımlı değildir. İlgili namespace kapsamdayken derleyici statik uzantıyı bulur. Her çağrı yeni bir kayıt oluşturur; burada paylaşılan, değiştirilebilir bir global nesne yoktur.

`DisplayName` de saklanan bir alan değildir. Her erişimde adları kırpıp sonucu hesaplar. Bu ayrım, özellikle özellik içine pahalı bir veritabanı sorgusu koymayı düşündüğünüzde önemlidir: **basit görünen bir özellik, beklenmedik I/O işlemi saklamamalıdır.**

## 4\. Koleksiyonlara anlamlı bir özellik eklemek

Uzantı blokları generic tiplerle de kullanılabilir:

```csharp
namespace CSharp2026.ExtensionMembers;

public static class CollectionExtensions
{
    extension<T>(IReadOnlyCollection<T> source)
    {
        public bool HasItems
        {
            get
            {
                ArgumentNullException.ThrowIfNull(source);
                return source.Count > 0;
            }
        }
    }
}

```

Örneğin:

```csharp
var customers = new List<Customer> { new("Ada", "Lovelace") };
Console.WriteLine(customers.HasItems); // True

```

Burada özellikle `IReadOnlyCollection<T>` seçtik. `Count` üzerinden kontrol yapabiliyoruz; diziyi baştan dolaşmamız gerekmiyor. Sadece `IEnumerable<T>` kabul edip her erişimde `Any()` çağıran bir özellik, kaynağa bağlı olarak yeniden numaralandırma yapabilir. Üyenin adı kadar kabul ettiği arayüz de davranışı belirler.

Bununla birlikte bu örnek, projedeki her koleksiyona `HasItems` eklenmesi gerektiği anlamına gelmez. `Count > 0` zaten yeterince açıksa ek bir soyutlama gereksiz olabilir.

## 5\. Tasarımda dikkat edilecek sınırlar

Extension üyeleri tipe gerçekten yeni alanlar eklemez ve kapsüllemeyi aşmaz. Private üyelere erişim yetkisi vermez; virtual davranışın yerini de almaz. İsim ve imza uyuştuğunda tipin kendi üyesi uzantıdan önceliklidir.

Bir başka önemli nokta **namespace kapsamıdır**. Gerekli `using` yoksa uzantı görünmez. Çok genel bir `Extensions` namespace’i, uygulamanın her yerine beklenmedik üyeler yayabilir. Katmana özgü ve açık isimler kullanmak daha sağlıklı bir tercihtir.

Şu ayrımı koruyun:

- Kural modelin her kullanımında geçerliyse, kaynak kod sizin kontrolünüzdeyse doğrudan model üyesi düşünün.
- Davranış sadece sunum, raporlama veya belirli bir uygulama katmanına aitse uzantı uygun olabilir.
- Zaten açık olan bir ifadeyi tek satır kısaltmak için yeni bir API oluşturmayın.

Örnekteki `ThrowIfNull`, alıcı nesnenin null olmasını yakalar. Bu, `FirstName` ve `LastName` için kapsamlı veri doğrulaması değildir. Dışarıdan gelen veriler model oluşturulurken ayrıca doğrulanmalıdır; nullable anotasyonları tek başına çalışma zamanı garantisi sağlamaz.

## Sonuç: yenilikten çok niyeti görünür kılın

C# 14 extension blokları; ilişkili yardımcı üyeleri bir arada toplamak, hesaplanan değerleri özellik olarak ifade etmek ve statik yardımcıları tip üzerinden çağırmak için kullanışlıdır. Kazanç, yalnızca daha az karakter yazmak değil, çağıran kodda **niyetin daha kolay okunmasıdır**.

[Üç makalenin çalıştırılabilir kod örneklerini indir — ZIP](https://hasan-aytac.com/content/files/2026/10/csharp-2026-code-samples.zip). Bu makalenin `ExtensionMembers` projesinde normal kullanım, boş koleksiyon, klasik sözdizimi ve null alıcı davranışı için yedi doğrulama bulunur.

## Kaynaklar ve devamı

- [Microsoft Learn — C# 14 yenilikleri](https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-14?ref=hasan-aytac.com)
- [Microsoft Learn — Extension members](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods?ref=hasan-aytac.com)
- [Microsoft Learn — Dil sürümünü yapılandırma](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/configure-language-version?ref=hasan-aytac.com)
- Serinin ikinci yazısı: [field ve null-conditional assignment](https://hasan-aytac.com/csharp-2026-field-null-conditional-assignment/).
- Serinin üçüncü yazısı: [async streams ve cancellation](https://hasan-aytac.com/csharp-2026-async-streams-cancellation/).

*Bu yazı yapay zekâ desteğiyle hazırlanmıştır. İndirilebilir örnekler .NET SDK 10.0.401 üzerinde, C# 14 ayarı ve uyarıları hata kabul eden yapılandırmayla derlenip çalıştırılmıştır.*