Rehber: Null ve null olmayan başvuru türleriyle tasarım amacınızı daha net ifade etme
Null yapılabilir başvuru türleri, null yapılabilir değer türlerinin değer türlerini tamamladığı gibi başvuru türlerini tamamlar. Türüne bir ?
ekleyerek bir değişkeni null atanabilir başvuru türü olarak bildirirsiniz. Örneğin, string?
null yapılabilir bir string
temsil eder. Tasarım amacınızı daha net ifade etmek için bu yeni türleri kullanabilirsiniz: bazı değişkenlerin her zamanbir değeri olmalıdır, diğerleri değeri eksik olabilir.
Bu öğreticide şunları nasıl yapacağınızı öğreneceksiniz:
- Tasarımlarınıza null değer atanabilir ve null değer atanamayan başvuru türlerini ekleyin
- Kodunuz genelinde null atanabilir başvuru türü denetimlerini etkinleştirin.
- Derleyicinin bu tasarım kararlarını zorunlu kıldığı kod yazın.
- Kendi tasarımlarınızda null atanabilir referans özelliğini kullanın.
Önkoşullar
C# derleyicisi de dahil olmak üzere makinenizi .NET çalıştıracak şekilde ayarlamanız gerekir. C# derleyicisi Visual Studio 2022veya .NET SDKile kullanılabilir.
Bu öğreticide, Visual Studio veya .NET CLI dahil olmak üzere C# ve .NET hakkında bilgi sahibi olduğunuz varsayılır.
Null değer atanabilir başvuru türlerini tasarımlarınıza dahil edin
Bu öğreticide, anket çalıştırmayı modelleyen bir kitaplık oluşturacaksınız. Kod, gerçek dünya kavramlarını temsil etmek için hem null olabilen referans türlerini hem de null olamayan referans türlerini kullanır. Anket soruları hiçbir zaman boş olamaz. Yanıtlayan bir soruyu yanıtlamamayı tercih edebilir. Yanıtlar bu durumda null
olabilir.
Bu örnek için yazdığınız kod bu amacı gösterir ve derleyici bu amacı uygular.
Uygulamayı oluştur ve null atanabilir referans türlerini etkinleştir
dotnet new console
kullanarak Visual Studio'da veya komut satırından yeni bir konsol uygulaması oluşturun. Uygulamayı NullableIntroduction
olarak adlandırın. Uygulamayı oluşturduktan sonra, projenin tamamının etkinnull atanabilir ek açıklama bağlamında derleneceğini belirtmeniz gerekir.
.csproj dosyasını açın ve PropertyGroup
öğesine bir Nullable
öğesi ekleyin. değerini enable
olarak ayarlayın. C# 11'den önceki projelerde null atanabilir başvuru türleri özelliğini etkinleştirmeniz gerekir. Bunun nedeni, özellik açıldıktan sonra var olan başvuru değişkeni bildirimlerinin null atanamayan başvuru türleriolmasıdır. Bu karar, mevcut kodun düzgün null denetimlere sahip olmadığı sorunları bulmaya yardımcı olsa da, özgün tasarım amacınızı doğru yansıtmayabilir:
<Nullable>enable</Nullable>
.NET 6'nın öncesinde, yeni projeler Nullable
öğesini içermez. .NET 6 ile başlayarak, yeni projeler proje dosyasındaki <Nullable>enable</Nullable>
öğesini içerir.
Uygulama türlerini tasarlama
Bu anket uygulaması birkaç sınıf oluşturmayı gerektirir:
- Soru listesini modelleyen bir sınıf.
- Anket için iletişim kuran kişilerin listesini modelleyen bir sınıf.
- Anketi dolduran bir kişinin yanıtlarını modelleyen bir sınıf.
Bu türler, hangi üyelerin gerekli olduğunu ve hangi üyelerin isteğe bağlı olduğunu ifade etmek için hem null atanabilir hem de null atanamaz başvuru türlerini kullanır. Null değer alabilen başvuru türleri, bu tasarım amacını açıkça iletir.
- Anketin parçası olan sorular hiçbir zaman null olamaz: Boş bir soru sormak mantıklı değildir.
- Yanıtlayanlar hiçbir zaman null olamaz. İletişim kurduğun kişileri, hatta katılmayı reddeden yanıtlayanları izlemek isteyeceksiniz.
- Bir soruya verilen yanıt null olabilir. Yanıtlayanlar soruların bazılarını veya tümünü yanıtlamayı reddedebilir.
C# dilinde programladıysanız, null
değerlere izin veren başvuru türlerine o kadar alışkın olabilirsiniz ki, null değer atanamayan örnekleri bildirmeye yönelik diğer fırsatları kaçırmış olabilirsiniz:
- Soru koleksiyonu null olmayan olmalıdır.
- Yanıtlayanların koleksiyonu null olamaz.
Kodu yazarken, referanslar için varsayılan olarak null olmayan bir referans türünün NullReferenceExceptionneden olabilecek yaygın hatalardan kaçındığını fark edeceksiniz. Bu öğreticiden çıkarabileceğiniz bir ders, hangi değişkenlerin null
olabileceğine veya olamayacağına dair kararlar vermenizdir. Dil, bu kararları ifade etmek için söz dizimi sağlamadı. Şimdi de var.
Oluşturabileceğiniz uygulama aşağıdaki adımları uygular:
- Anket oluşturur ve bu ankete sorular ekler.
- Anket için sahte rastgele bir yanıtlayan kümesi oluşturur.
- Tamamlanan anket boyutu hedef numaraya ulaşana kadar yanıtlayanlarla iletişime geçer.
- Anket yanıtlarıyla ilgili önemli istatistikleri yazar.
Anketi null atanabilir ve boş değer atanamayan başvuru türleriyle oluşturma
Yazacak ilk kod anketi oluşturur. Anket sorusunu ve anket yürütmesini modellemek için sınıflar yazacaksınız. Anketinizde yanıtın biçimiyle ayırt edilen üç soru türü vardır: Evet/Hayır yanıtları, sayı yanıtları ve metin yanıtları.
public SurveyQuestion
sınıfı oluşturma:
namespace NullableIntroduction
{
public class SurveyQuestion
{
}
}
Derleyici, her başvuru türü değişken bildirimini, null atanabilir ek açıklama bağlamındaki kod için null atanamaz başvuru türü olarak yorumlar. Aşağıdaki kodda gösterildiği gibi soru metninin özelliklerini ve soru türünü ekleyerek ilk uyarınızı görebilirsiniz:
namespace NullableIntroduction
{
public enum QuestionType
{
YesNo,
Number,
Text
}
public class SurveyQuestion
{
public string QuestionText { get; }
public QuestionType TypeOfQuestion { get; }
}
}
QuestionText
'ı başlatmadığınızdan, derleyici null atanamayan bir özelliğin başlatılmadığını belirten bir uyarı verir. Tasarımınız soru metninin null olmayan olmasını gerektirdiğinden, bunu başlatmak için bir oluşturucu ve QuestionType
değeri de eklersiniz. Tamamlanmış sınıf tanımı aşağıdaki koda benzer:
namespace NullableIntroduction;
public enum QuestionType
{
YesNo,
Number,
Text
}
public class SurveyQuestion
{
public string QuestionText { get; }
public QuestionType TypeOfQuestion { get; }
public SurveyQuestion(QuestionType typeOfQuestion, string text) =>
(TypeOfQuestion, QuestionText) = (typeOfQuestion, text);
}
Oluşturucunun eklenmesi uyarıyı kaldırır. Oluşturucu argümanı da null olmayan bir referans türüdür, bu yüzden derleyici herhangi bir uyarı vermez.
Ardından, SurveyRun
adlı bir public
sınıfı oluşturun. Bu sınıf, aşağıdaki kodda gösterildiği gibi ankete soru eklemek için SurveyQuestion
nesnelerinin ve yöntemlerinin listesini içerir:
using System.Collections.Generic;
namespace NullableIntroduction
{
public class SurveyRun
{
private List<SurveyQuestion> surveyQuestions = new List<SurveyQuestion>();
public void AddQuestion(QuestionType type, string question) =>
AddQuestion(new SurveyQuestion(type, question));
public void AddQuestion(SurveyQuestion surveyQuestion) => surveyQuestions.Add(surveyQuestion);
}
}
Daha önce olduğu gibi, liste nesnesini null olmayan bir değere başlatmanız gerekir veya derleyici bir uyarı verir. Null denetimleri yoktur çünkü AddQuestion
'ın ikinci aşırı yüklemesinde bu gerekli değildir: Bu değişkeni null atanamaz olarak bildirdiniz. Değeri null
olamaz.
Düzenleyicinizde Program.cs geçin ve Main
içeriğini aşağıdaki kod satırlarıyla değiştirin:
var surveyRun = new SurveyRun();
surveyRun.AddQuestion(QuestionType.YesNo, "Has your code ever thrown a NullReferenceException?");
surveyRun.AddQuestion(new SurveyQuestion(QuestionType.Number, "How many times (to the nearest 100) has that happened?"));
surveyRun.AddQuestion(QuestionType.Text, "What is your favorite color?");
Projenin tamamı null kontrolü yapılabilir ek açıklamalar bağlamında olduğu için, null
'ı null kontrollü olmayan bir başvuru türü bekleyen herhangi bir yönteme geçirdiğinizde uyarılar alırsınız.
Main
aşağıdaki satırı ekleyerek deneyin:
surveyRun.AddQuestion(QuestionType.Text, default);
Yanıtlayanlar oluşturma ve ankete yanıt alma
Ardından, ankete yanıt oluşturan kodu yazın. Bu işlem birkaç küçük görev içerir:
- Yanıtlayan nesneler oluşturan bir yöntem oluşturun. Bunlar anketi doldurmak isteyen kişileri temsil eden kişilerdir.
- Yanıtlayana soru sorma ve yanıt toplama ya da yanıtlayanın yanıt vermediğini belirtme simülasyonu yapmak için mantık oluşturun.
- Anketi yeterli sayıda katılımcı yanıtlayana kadar tekrarlayın.
Anket yanıtlarını temsil etmek için bir sınıfınız olması gerekir, bu nedenle bunu şimdi ekleyin. Nullable desteğini etkinleştirin. Aşağıdaki kodda gösterildiği gibi bir Id
özelliği ve bunu başlatan bir oluşturucu ekleyin:
namespace NullableIntroduction
{
public class SurveyResponse
{
public int Id { get; }
public SurveyResponse(int id) => Id = id;
}
}
Ardından, rastgele bir kimlik oluşturarak yeni katılımcılar oluşturmak için bir static
yöntemi ekleyin:
private static readonly Random randomGenerator = new Random();
public static SurveyResponse GetRandomId() => new SurveyResponse(randomGenerator.Next());
Bu sınıfın temel sorumluluğu, anketteki sorulara bir katılımcının yanıtlarını oluşturmaktır. Bu sorumluluğun birkaç adımı vardır:
- Ankete katılmayı isteyin. Kişi onay vermezse, eksik (veya boş) bir yanıt döndürün.
- Her soruyu sorun ve yanıtı kaydedin. Her yanıt da eksik (veya null) olabilir.
SurveyResponse
sınıfınıza aşağıdaki kodu ekleyin:
private Dictionary<int, string>? surveyResponses;
public bool AnswerSurvey(IEnumerable<SurveyQuestion> questions)
{
if (ConsentToSurvey())
{
surveyResponses = new Dictionary<int, string>();
int index = 0;
foreach (var question in questions)
{
var answer = GenerateAnswer(question);
if (answer != null)
{
surveyResponses.Add(index, answer);
}
index++;
}
}
return surveyResponses != null;
}
private bool ConsentToSurvey() => randomGenerator.Next(0, 2) == 1;
private string? GenerateAnswer(SurveyQuestion question)
{
switch (question.TypeOfQuestion)
{
case QuestionType.YesNo:
int n = randomGenerator.Next(-1, 2);
return (n == -1) ? default : (n == 0) ? "No" : "Yes";
case QuestionType.Number:
n = randomGenerator.Next(-30, 101);
return (n < 0) ? default : n.ToString();
case QuestionType.Text:
default:
switch (randomGenerator.Next(0, 5))
{
case 0:
return default;
case 1:
return "Red";
case 2:
return "Green";
case 3:
return "Blue";
}
return "Red. No, Green. Wait.. Blue... AAARGGGGGHHH!";
}
}
Anket yanıtlarının depolanması için kullanılan Dictionary<int, string>?
, null olabileceğini belirten bir değer anlamına gelir. Tasarım amacınızı hem derleyiciye hem de kodunuzu daha sonra okuyan herkese bildirmek için yeni dil özelliğini kullanıyorsunuz. Önce null
değerini kontrol etmeden surveyResponses
referansını çözerseniz, bir derleyici uyarısı alırsınız. Derleyici surveyResponses
değişkeninin yukarıdaki null olmayan bir değere ayarlandığını belirleyebildiğinden AnswerSurvey
yönteminde uyarı almazsınız.
Eksik yanıtlar için null
kullanılması, null atanabilir başvuru türleriyle çalışmanın önemli bir noktasını vurgular: amacınız tüm null
değerlerini programınızdan kaldırmak değildir. Bunun yerine, amacınız yazdığınız kodun tasarımınızın amacını ifade etmesini sağlamaktır. Eksik değerler, kodunuzda ifade etmek için gerekli bir kavramdır.
null
değeri, bu eksik değerleri ifade etmenin net bir yoludur. Tüm null
değerlerini kaldırmaya çalışmak, eksik değerleri null
olmadan ifade etmek için başka bir yol tanımlamaya neden olur.
Ardından, SurveyRun
sınıfında PerformSurvey
yöntemini yazmanız gerekir.
SurveyRun
sınıfına aşağıdaki kodu ekleyin:
private List<SurveyResponse>? respondents;
public void PerformSurvey(int numberOfRespondents)
{
int respondentsConsenting = 0;
respondents = new List<SurveyResponse>();
while (respondentsConsenting < numberOfRespondents)
{
var respondent = SurveyResponse.GetRandomId();
if (respondent.AnswerSurvey(surveyQuestions))
respondentsConsenting++;
respondents.Add(respondent);
}
}
Burada da null atanabilir bir List<SurveyResponse>?
seçeneğiniz yanıtın null olabileceğini gösterir. Bu, anketin henüz yanıtlayanlara verilmediğini gösterir. Yeterli onay verene kadar yanıtlayanların eklendiğine dikkat edin.
Anketi çalıştırmanın son adımı, Main
yönteminin sonunda anketi gerçekleştirmek için bir çağrı eklemektir:
surveyRun.PerformSurvey(50);
Anket yanıtlarını inceleme
Son adım anket sonuçlarını görüntülemektir. Yazdığınız sınıfların çoğuna kod ekleyeceksiniz. Bu kod, null atanabilir ve boş değer atanamayan başvuru türlerini ayırt etme değerini gösterir.
SurveyResponse
sınıfına aşağıdaki iki ifade gövdeli üye ekleyerek başlayın:
public bool AnsweredSurvey => surveyResponses != null;
public string Answer(int index) => surveyResponses?.GetValueOrDefault(index) ?? "No answer";
surveyResponses
null atanabilir bir başvuru türü olduğundan, başvuru çözümlemesi yapmadan önce null kontrolü gereklidir.
Answer
yöntemi null atanamaz bir dize döndürür, bu nedenle null birleşim işlecini kullanarak eksik yanıt durumunu ele alacağız.
Ardından, SurveyRun
sınıfına şu üç ifade gövdeli üyeyi ekleyin:
public IEnumerable<SurveyResponse> AllParticipants => (respondents ?? Enumerable.Empty<SurveyResponse>());
public ICollection<SurveyQuestion> Questions => surveyQuestions;
public SurveyQuestion GetQuestion(int index) => surveyQuestions[index];
AllParticipants
üyesi, respondents
değişkeninin null olabileceğini, ancak dönüş değerinin null olamaz olduğunu dikkate almalıdır. Bu ifadeyi ??
ve ardından gelen boş diziyi kaldırarak değiştirirseniz, derleyici yöntemin null
döndürebileceği ve dönüş imzasının null atanamaz bir tür döndüreceği konusunda sizi uyarır.
Son olarak, Main
yönteminin en altına aşağıdaki döngünün eklenmesini sağlar:
foreach (var participant in surveyRun.AllParticipants)
{
Console.WriteLine($"Participant: {participant.Id}:");
if (participant.AnsweredSurvey)
{
for (int i = 0; i < surveyRun.Questions.Count; i++)
{
var answer = participant.Answer(i);
Console.WriteLine($"\t{surveyRun.GetQuestion(i).QuestionText} : {answer}");
}
}
else
{
Console.WriteLine("\tNo responses");
}
}
Bu kodda hiçbir null
denetimine ihtiyacınız yoktur, çünkü temel arabirimleri tümünün null atanamaz başvuru türleri döndürmesi için tasarladınız.
Kodu al
Tamamlanmış öğreticinin kodunu csharp/NullableIntroduction klasöründeki örnekleri depomuzdan alabilirsiniz.
Null atanabilir ve null atanamayan başvuru türleri arasındaki tür bildirimlerini değiştirerek denemeler yapın. yanlışlıkla bir null
'e başvurmadığınızdan emin olmak için bu işlemin nasıl farklı uyarılar ürettiğini görün.
Sonraki adımlar
Entity Framework kullanırken null atanabilir referans türünü kullanmayı öğrenin.