Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Tip
Yazılım geliştirme konusunda yeni misiniz? Başlangıç öğreticileriyle işe başlayın.
Başka bir dilde mi deneyimlisiniz? Kotlin’deki null olabilir türlerle, TypeScript’in strictNullChecks yapısıyla veya Swift’teki isteğe bağlı türlerle çalıştıysanız, bu model size tanıdık gelecektir. C# ayrı bir tür yerine statik analiz ve uyarı tanılamaları kullanır.
Ek açıklamalarla amacı ifade etme ve null durumu analizi bölümlerine göz atın, ardından özelliği uygulamak için Öğretici: Null atanabilir ve null atanamaz başvuru türleriyle tasarım amacınızı ifade etme bölümüne geçin.
Boş değer atanabilir başvuru türleri, kodunuzun System.NullReferenceException hatası verme olasılığını azaltan bir özellik grubudur. Hangi değişkenlerin null değerini tutmasının amaçlandığını ve hangilerinin amaçlanmadığını belirtirsiniz; derleyici de bu bildirimler kodunuzun bunları kullanma biçimiyle eşleşmediğinde sizi uyarır. Programınızın çalışma zamanı davranışı değişmedi. Boş değer atanabilir referans türleri tamamen derleme zamanına ait bir özelliktir.
Üç yapı taşları birlikte çalışır:
-
Değişken ek açıklamaları (
stringvestring?), hangi referanslarınnullişlemine izin vermeyi amaçladığını gösterir. - Null durum çözümlemesi, bir ifadenin değerinin kodunuzun her noktasında null veya belki de nullolmadığını izler.
-
API'lerdeki öznitelikler , "bu bağımsız değişken olabilir
null, ancak dönüş değeri yalnızca bağımsız değişken null olduğunda null olur" gibi daha fazla nüanslı sözleşmeyi açıklar.
Derleyici, tanılama oluşturmak için bu sinyalleri birleştirir. Null değer atanamayan bir değişkendeki uyarılar, değişkenin alabileceği nullanlamına gelir. Null atanabilir bir değişkenle ilgili uyarılar, kodun null denetimi yapmadan ona doğrudan erişebileceği anlamına gelir.
Dereference, değişkenin işaret ettiği değeri kullanmak anlamına gelir. Örneğin, onda bir yöntemi çağırmak (variable.Method()), bir özelliği okumak (variable.Property) veya ona dizinle erişmek (variable[0]) için. Değeri null olan bir değişkenin başvurusunun kaldırılması, çalışma zamanında bir özel durum oluşturur. Her iki tür uyarı da kodun davranışının belirtilen tasarımıyla eşleşmediği anlamına gelir.
Null atanabilir bağlam
Son .NET şablonlarından oluşturulan projeler, proje dosyasında <Nullable>enable</Nullable> ayarlar, bu nedenle bu makaledeki yönergeler yazıldıkları gibi geçerlidir. Daha eski bir projede çalışıyorsanız .csproj öğesini açın ve <PropertyGroup> öğesinin aşağıdaki satırı içerdiğini kontrol edin; eksikse ekleyin:
<Nullable>enable</Nullable>
Büyük bir uygulamayı geçirme hakkında daha fazla bilgi için daha fazla ayar ve yönerge için null atanabilir geçiş stratejileri makalesine bakın.
Ek açıklamalarla amacınızı ifade edin
Her başvuru türü değişkeni varsayılan olarak null olamaz.
? ekleyerek null atanabilir başvuru türü bildirin:
public static void Annotations()
{
string required = "always set"; // non-nullable: assigning null produces a warning
string? optional = null; // nullable: holding null is allowed
Console.WriteLine(required.Length);
if (optional is not null)
{
Console.WriteLine(optional.Length);
}
}
Ek açıklama çalışma zamanı türünü değiştirmez.
string ve string? her ikisi de System.Stringşeklindedir. , ? derleyiciye tasarım amacınızı bildirir. Bu amaç, derleyicinin ürettiği uyarıları şekillendirir:
- Null atanamayan bir değişkenin varsayılan null durumunull değil'dir.
nullolabilecek bir değer atarsanız derleyici uyarı verir. - Null atanabilen bir değişkenin varsayılan null durumunull olabilir'dir. Derleyici, değişkenin başvurusunu önce denetlemeden çözümlemeniz durumunda uyarı verir.
Tür sisteminde gerekli ve isteğe bağlı değerleri görünür hale getirmek için ek açıklamayı kullanın. Aşağıdaki Person türü, FirstName ile LastName’yi null atanamaz olarak bildirir—her kişinin ikisine de sahip olması gerekir—ve MiddleName’ü ise null atanabilir olarak bildirir; çünkü herkeste bir tane bulunmaz:
public sealed class Person(string firstName, string lastName)
{
public string FirstName { get; } = firstName;
public string? MiddleName { get; init; }
public string LastName { get; } = lastName;
public override string ToString() => MiddleName is null
? $"{FirstName} {LastName}"
: $"{FirstName} {MiddleName} {LastName}";
}
public static void DesignIntent()
{
Person p1 = new("Ada", "Lovelace") { MiddleName = "King" };
Console.WriteLine(p1);
// Output: Ada King Lovelace
Person p2 = new("Grace", "Hopper");
Console.WriteLine(p2);
// Output: Grace Hopper
}
Açıklamalar, ToString öğesinin uygulanmasına yön verir.
FirstName ve LastName null olamaz olduğundan, geçersiz kılma bunları null denetimi olmadan doğrudan araya ifade eklenmiş bir dizede ($"..." söz dizimiyle ifadeleri {} yer tutucularına ekleyerek) kullanır.
MiddleName null atanabilir olduğundan, geçersiz kılma işlemi önce bunu null ile denetler ve yalnızca varsa dahil eder. Derleyici bu ayrımı uygular: null atanamaz bir değerin beklendiği bir yerde null olabilecek bir değer geçiren kod uyarı üretir; ayrıca, null atanamaz bir üyeyi başlatmadan bırakan bir oluşturucu da uyarı üretir.
Null durum analizi
Derleyici, her ifadenin null durumunu izler. Durum iki değerden biridir:
-
not-null: ifadenin
nullolmadığı bilinmektedir. -
belki-null: ifadesi olabilir
null.
Derleyici kodunuzu analiz ettikçe yerel değişkenin null durumu güncelleştirilir. İki şey bunu değiştirir: atamalar ve null kontrolleri. Atamadan sonra değişkenin null durumu sağ taraftaki ifadeyle eşleşir. İfade null ise veya null olabilirse, değişken muhtemelen null olur. İfade null olmayan bir literal ise, değişken null değil hâle gelir. Null denetiminden sonra, değişkenin null durumu hangi dal seçilirse seçilsin onu yansıtır.
public static void NullStateTracking()
{
string? message = null;
// Warning: dereference of a possibly null reference.
Console.WriteLine(message.Length);
message = "Hello, World!";
// No warning: the compiler tracks that message is now not-null.
Console.WriteLine(message.Length);
}
Yukarıdaki örnekte ilk başvuru, message olduğundan bir uyarı oluşturur. Null olmayan bir değişmez değere atamadan sonra, derleyici message bilir, bu nedenle ikinci başvuru güvenlidir.
Null durumu çözümlemesi, if denetimlerde, desen eşleştirmede (bir değerin şeklini sınayan is null veya is { } gibi ifadelerde) ve döngüye giren veya erken dönen denetim akışında çalışır:
public sealed class Node(string name)
{
public string Name { get; } = name;
public Node? Parent { get; init; }
}
public static void FlowAnalysis(Node start)
{
Node? current = start;
while (current is not null)
{
// Inside the loop, the compiler knows current is not-null.
Console.WriteLine(current.Name);
current = current.Parent;
}
}
Analiz, yöntem gövdelerinin içine inmez. Çağıranlara null durumunu iletmek için bir yönteme ihtiyacınız varsa, imzasında null atanabilirlik çözümleme özniteliklerini kullanın.
Uyarıları ! ile geçersiz kılın
Bazen derleyiciden daha fazlasını bilirsiniz.
Null-forgiving işleci!, analiz aksini söylediğinde bile ifadenin null olmadığını bildirir:
public static void NullForgiving()
{
// "ada" matches a switch arm that returns a non-null string,
// but the return type is string? so the compiler treats the
// result as maybe-null.
string? maybeName = LookUpName("ada");
// The ! tells the compiler "trust me, this isn't null." We just
// passed "ada", which the switch maps to "Ada Lovelace".
int length = maybeName!.Length;
Console.WriteLine(length); // => 12
}
// Returns string? because the wildcard arm yields null.
private static string? LookUpName(string id) => id switch
{
"ada" => "Ada Lovelace",
_ => null,
};
! ögesini tedbirli kullanın. Her kullanım, derleyicinin artık sizi koruyamadığı bir noktadır. Null denetim eklemeyi, kodu yeniden yapılandırmayı veya derleyicinin kendi başına doğru sonuca ulaşması için ilgili API'ye açıklama eklemeyi tercih edin.
API sözleşmelerini açıklayan öznitelikler
Bir parametre veya dönüş türündeki ek açıklamalar her zaman yeterince açıklayıcı değildir. Bir yöntem, null olabilen bir argümanı kabul edebilir ancak null olmayan bir sonucu garanti edebilir. Bir test yöntemi, yalnızca bağımsız değişkeni null değilse true döndürebilir. Bu sözleşmeleri iletmek için null atanabilir analiz özniteliklerini kullanın:
public static bool IsPresent([NotNullWhen(true)] string? value) =>
!string.IsNullOrEmpty(value);
public static void NullAnalysisAttributes()
{
string? input = ReadInput();
if (IsPresent(input))
{
// No null-forgiving operator needed: the attribute tells the compiler
// input is not-null when IsPresent returns true.
Console.WriteLine(input.Length);
}
}
private static string? ReadInput() => "hello";
NotNullWhenAttribute, IsPresenttrue döndürdüğünde bağımsız değişkenin null olmadığını derleyiciye bildirir.
if bloğunun içinde, derleyici value öğesini, null bağışlayıcı işleci gerekmeden not-null olarak değerlendirir. .NET 5 itibarıyla tüm .NET çalışma zamanı API'lerine açıklama eklenir, bu nedenle analiz onları çağıran tüm kodlardan yararlanır.
Bilinen tuzaklar
İki desen, null atanamaz bir referansın uyarı vermeden null değerini tutmasına neden olabilir. Her iki desen de statik çözümlemenin sınırlamalarıdır, kodunuzdaki hatalar değildir.
Öntanımlı Yapılar
default veya new() kullanarak null atanamayan başvuru alanlarına sahip bir yapı oluşturabilirsiniz. Bu yaklaşım, yapının alanlarını başlatılmamış olarak bırakır:
public struct Student
{
public string FirstName;
public string? MiddleName;
public string LastName;
}
public static void DefaultStructPitfall()
{
Student s = default; // No warning, but FirstName and LastName are null.
Console.WriteLine(s.FirstName?.Length ?? -1);
}
Alanlar çalışma zamanında null içerir, ancak derleyici uyarı vermez. Bir yapı kullanmanız gerekiyorsa, çağıranın bir nesne başlatıcısı aracılığıyla başlatmak zorunda olduğu gerekli üyeleri ya da çağıranların kullanmak zorunda olduğu parametreli bir oluşturucuyu tercih edin.
Referans ve yapı dizileri
Null değer atanamayan başvuru türünde yeni bir dizi, siz her birini atayana kadar tüm null öğeleri içerir:
public static void ArrayPitfall()
{
string[] values = new string[3]; // Elements are null at run time.
Console.WriteLine(values[0]?.Length ?? -1);
string[] initialized = ["a", "b", "c"]; // Collection expression initializes every slot.
Console.WriteLine(initialized[0].Length);
}
Aynı tuzak struct dizileri için de geçerlidir: her öğe başlangıçta struct'ın varsayılan değerine sahiptir, bu nedenle her öğenin null atanamayan başvuru türündeki alanları başlangıçta null olur.
Dizi oluşturma işleminin bir parçası olarak dizi öğelerini başlatın.
Koleksiyon ifadeleri ([1, 2, 3] sabit söz dizimi) ve hedef türü çıkarımlı new (derleyici türü çıkarabildiğinde new() yazılması), tam başlatmayı kısa ve öz hâle getirir.