C# null işleçleri

Tip

Bu makale, en az bir programlama dili bilen ve C# dilini öğrenen geliştiriciler için Temel Bilgiler bölümünün bir parçasıdır. Programlamaya yeni başladıysanız ilk olarak Başlangıç öğreticileri ile başlayın. Tam operatör referansı için bkz. dil referansında Üye erişim operatörleri ve null birleştirme operatörleri.

C# null güvenli kodu kısa hale getiren birkaç işleç sağlar. Bu işleçler, tüm kod boyunca iç içe if (x != null) korumalar kullanmak yerine null güvenliğine sahip erişim, yedek değerler ve null testlerini tek bir ifadede ifade etmenizi sağlar.

Bu makale ?.?[] null koşullu erişim,?? null birleştirme, ??= null birleştirme ataması ve is null/is not null null desen eşleştirmeyi kapsar.

Null koşullu üye erişimi ?.

?. işleci, yalnızca nesne null olmadığında bir üyeye erişir. Nesne null olduğunda, ifadenin tamamı bir null olarak değerlendirilir; NullReferenceException fırlatmak yerine.

string? name = null;

// Without ?., accessing a member on null throws NullReferenceException:
// int len = name.Length; // throws if name is null

// ?. returns null instead of throwing:
int? len = name?.Length;
Console.WriteLine(len.HasValue); // False

name = "C#";
Console.WriteLine(name?.Length); // 2

Operatör ?.kısa devre yapar: Sol taraf null olduğunda, sağ taraftaki tüm işlemler atlanır. Hiçbir yöntem çağrısı çalıştırılmaz ve yan etkiler oluşmaz.

Tek bir ifadede birden çok ?. işleci zincirleyebilirsiniz. Zincir, karşılaştığı ilk null'da durur.

string? input = null;

// Chain ?. across multiple method calls — short-circuits at the first null:
string? upper = input?.Trim()?.ToUpperInvariant();
Console.WriteLine(upper ?? "(none)"); // (none)

input = "  hello  ";
Console.WriteLine(input?.Trim()?.ToUpperInvariant()); // HELLO

Null koşullu indeksleyici erişimi ?[]

?[] işleci dizinleyiciye ve dizi erişimine aynı kısa devre davranışını uygular. Koleksiyonun kendisi null olabilirken kullanın.

string[]? tags = null;

// ?[] accesses an element only when the collection is non-null
string? first = tags?[0];
Console.WriteLine(first ?? "(none)"); // (none)

tags = ["csharp", "dotnet", "nullable"];
Console.WriteLine(tags?[0]);          // csharp

Null koşullu işleçleri zincirleme

Birden çok ?. işleci zincirleyerek null olabilecek başvuruların yolunu aşın. Zincir ilk null'de kısa devre yapar.

var order = new Order("ORD-001", null);

// Each ?. short-circuits when null: Customer is null, so Address and City are never accessed
string? city = order.Customer?.Address?.City;
Console.WriteLine(city ?? "(no city)"); // (no city)

var fullOrder = new Order("ORD-002",
    new Customer("Alice", new Address("123 Main St", "Springfield", "IL")));

Console.WriteLine(fullOrder.Customer?.Address?.City); // Springfield

Eğer Customer ise, ne null ne de Address değerlendirilir. İfadenin tamamı null döndürür.

Thread güvenli temsilci çağırma

?. bir temsilciyi çağırmak veya bir olayı tetiklemek için temiz, iş parçacığı güvenli bir yol sağlar. Temsilci ifadesi yalnızca bir kez değerlendirilir, bu nedenle null denetim ile çağırma arasında başka bir iş parçacığının aboneliğini kaldırma penceresi yoktur:

EventHandler? clicked = null;

// No subscribers — ?.Invoke does nothing instead of throwing NullReferenceException
clicked?.Invoke(null, EventArgs.Empty);

clicked += (_, _) => Console.WriteLine("Button clicked!");

// With a subscriber — ?.Invoke calls the handler
clicked?.Invoke(null, EventArgs.Empty);
// Output: Button clicked!

Bu desen eski if (clicked != null) clicked(...) deyimin yerini alır.

Null birleştirme ??

?? işleci, sol işleneni null olmadığında sol işleneni, sol işleneni null olduğunda ise null sağ işleneni döndürür. Varsayılan bir değer sağlamak için bu değeri kullanın:

string? username = null;

// ?? returns the right-hand value when the left-hand is null
string display = username ?? "Guest";
Console.WriteLine(display); // Guest

username = "alice";
display  = username ?? "Guest";
Console.WriteLine(display); // alice

?? sağa doğru ilişkilendirilir, bu nedenle a ?? b ?? c, a ?? (b ?? c) olarak değerlendirilir. İlk null olmayan değer kazanır. ?. ile ?? zincirlemek yaygın bir desendir: null-olası bir zincirden güvenli bir şekilde geçiş yapmak için ?. kullanın ve zincir ?? döndürdüyse varsayılanı değiştirmek için null kullanın. Tam bir örnek için bkz. Null işleçleri birleştirme.

Null birleşim ataması ??=

??= işleci, yalnızca değişken null olduğunda sağ taraftaki değeri değişkene atar. Yavaş başlatma için kullanın:

List<string>? cache = null;

// ??= assigns only when the variable is null
cache ??= LoadData();
Console.WriteLine(cache.Count); // 3

// cache is already non-null, so LoadData() isn't called again
cache ??= LoadData();
Console.WriteLine(cache.Count); // 3

static List<string> LoadData() => ["alpha", "beta", "gamma"];

Değişken null olduğunda sağdaki ifade değerlendirilir. Değişkenin zaten bir değeri olduğunda, sağ taraf hiç değerlendirilmez.

Null koşullu atama (C# 14)

C# 14 ile başlayarak, ?. ve ?[]'yi atama hedefleri olarak kullanabilirsiniz. Atama yalnızca sol taraftaki nesne null olmadığında çalışır:

AppConfig? config = new AppConfig();

// Assigns only when config is non-null (C# 14)
config?.Theme = "dark";
Console.WriteLine(config?.Theme); // dark

AppConfig? missing = null;
missing?.Theme = "light";                         // no-op: missing is null
Console.WriteLine(missing?.Theme ?? "(no config)"); // (no config)

Sağ taraf, yalnızca sol tarafın NULL olmadığının bilindiğinde değerlendirilir.

Null desen eşleştirme: is null ve is not null

is null ve is not null desenleri bir ifadenin olup olmadığını test edernull:

string? input = null;

// is null is the preferred test — unaffected by operator overloading
if (input is null)
{
    Console.WriteLine("No input provided.");
}

// == null also works, but a custom == operator can change its behavior
if (input == null)
{
    Console.WriteLine("Still no input.");
}

Null denetimleri için is null yerine == null tercih edin. İşleç == aşırı yüklenebilir, yani tür özel bir eşitlik işleci tanımladığında, x == nulltrue olmadığında bile x, null'yi döndürebilir. Desen, is null işleç aşırı yüklemesine bakılmaksızın her zaman gerçek null başvuruyu kontrol eder.

string? value = "hello";

if (value is not null)
{
    Console.WriteLine(value.ToUpper()); // HELLO
}

Null işleçleri birleştirme

Pratikte, bu işleçlerden birkaçını genellikle birleştirirsiniz. Bir ifade derin bir nesne grafiğinden güvenli bir şekilde geçiş yapabilir, geri dönüş uygulayabilir ve ardından sonucu izleyebilir:

Order? order = GetPendingOrder();

// Chain ?. for safe traversal, ?? for a fallback, is null for a clear guard
string city = order?.Customer?.Address?.City ?? "unknown";

if (order is null)
{
    Console.WriteLine("No pending order.");
}
else
{
    Console.WriteLine($"Shipping to: {city}");
}
// Output: No pending order.

Null-forgiving işleci !

Postfix ! işleci null atanabilir uyarılarını bastırır. Derleyiciye "bu ifade kesinlikle null değil" demek için ekleyin ! . İşlecin çalışma zamanında hiçbir etkisi yoktur. Yalnızca derleyicinin null durum çözümlemesini etkiler.

string? name = FindUser("alice");

// Use ! only when you have information the compiler doesn't.
// FindUser guarantees a non-null result for known usernames.
int length = name!.Length;
Console.WriteLine(length); // 5

Yalnızca derleyicinin sahip olmadığı bilgilere sahip olduğunuzda ! dikkatli kullanın. Örnek olarak bağımsız değişken denetimi mantığını doğrulamak için kasıtlı olarak geçen null testler veya sözleşmesi bilinen bir giriş için null olmayan bir dönüş garanti eden bir yöntemi çağırma verilebilir. ! aşırı kullanımı, null atanabilir başvuru türlerinin amacını anlamsız hale getirir. Tam açıklama için bkz. Null atanabilir başvuru türleri.

Ayrıca bakınız