Aracılığıyla paylaş


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 stringtemsil 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 consolekullanarak Visual Studio'da veya komut satırından yeni bir konsol uygulaması oluşturun. Uygulamayı NullableIntroductionolarak 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 enableolarak 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 nullolabileceğ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:

  1. Anket oluşturur ve bu ankete sorular ekler.
  2. Anket için sahte rastgele bir yanıtlayan kümesi oluşturur.
  3. Tamamlanan anket boyutu hedef numaraya ulaşana kadar yanıtlayanlarla iletişime geçer.
  4. 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, SurveyRunadlı 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 nullolamaz.

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. Mainaş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:

  1. Yanıtlayan nesneler oluşturan bir yöntem oluşturun. Bunlar anketi doldurmak isteyen kişileri temsil eden kişilerdir.
  2. 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.
  3. 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:

  1. Ankete katılmayı isteyin. Kişi onay vermezse, eksik (veya boş) bir yanıt döndürün.
  2. 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 nullolmadan 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.