Öğretici: Boş değer atanabilir ve boş değer atanamayan başvuru türleriyle tasarım amacınızı daha net bir şekilde ifade etme

Boş değer atanabilir başvuru türleri , başvuru türlerini null atanabilir değer türlerinin değer türlerini tamamlayabilen şekilde tamamlar. Türüne bir ekleyerek ? bir değişkeni null atanabilir bir başvuru türü olarak bildirirsiniz. Örneğin, string? null atanabilir stringdeğerini temsil eder. Tasarım amacınızı daha net bir şekilde ifade etmek için bu yeni türleri kullanabilirsiniz: bazı değişkenlerin her zaman bir değeri olmalıdır, bazılarında değer eksik olabilir.

Bu öğreticide aşağıdakilerin nasıl yapılacağını öğreneceksiniz:

  • Null değer atanabilir ve boş değer atanamayan başvuru türlerini tasarımlarınıza dahil etmek
  • Kodunuzda boş değer atanabilir başvuru türü denetimlerini etkinleştirin.
  • Derleyicinin bu tasarım kararlarını zorunlu kıldığı bir kod yazın.
  • Null atanabilir başvuru özelliğini kendi tasarımlarınızda kullanma

Önkoşullar

C# derleyicisi de dahil olmak üzere makinenizi .NET'i çalıştıracak şekilde ayarlamanız gerekir. C# derleyicisi Visual Studio 2022 veya .NET SDK ile 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 ekleme

Bu öğreticide, anket çalıştıran modelleri içeren bir kitaplık oluşturacaksınız. Kod, gerçek dünya kavramlarını temsil etmek için hem null atanabilir başvuru türlerini hem de boş değer atanamayan başvuru türlerini kullanır. Anket soruları hiçbir zaman null olamaz. Yanıtlayan bir soruyu yanıtlamamayı tercih edebilir. Yanıtlar bu durumda olabilir null .

Bu örnek için yazacak kodunuz bu amacı ifade eder ve derleyici bu amacı zorlar.

Uygulamayı oluşturma ve boş değer atanabilir başvuru türlerini etkinleştirme

Visual Studio'da veya komutunu kullanarak dotnet new consolekomut satırından yeni bir konsol uygulaması oluşturun. Uygulamayı NullableIntroductionolarak adlandırın. Uygulamayı oluşturduktan sonra, tüm projenin boş değer atanabilir ek açıklama bağlamında derleneceğini belirtmeniz gerekir. .csproj dosyasını açın ve öğesine bir Nullable öğesi PropertyGroup ekleyin. Değerini enable olarak ayarlayın. C# 11'den önceki projelerde null atanabilir başvuru türleri özelliğini kabul etmeniz gerekir. Bunun nedeni, özellik açıldıktan sonra mevcut başvuru değişkeni bildirimlerinin null atanamaz başvuru türlerine dönüşmesidir. Bu karar, mevcut kodun düzgün null denetimlere sahip olmamasıyla ilgili 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 öğesini içermez Nullable . .NET 6 ile başlayarak, yeni projeler proje dosyasında öğesini <Nullable>enable</Nullable> 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 alan 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. Boş değer atanabilir başvuru türleri bu tasarım amacını açıkça iletir:

  • Anketin bir 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şime geçtiğiniz kişileri, hatta katılmayı reddeden yanıtlayanları izlemek istersiniz.
  • 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ğer atanamayan örnekleri bildirmek için başka fırsatları kaçırmış olabileceğiniz değerlere izin veren null başvuru türlerine çok alışkın olabilirsiniz:

  • Soru koleksiyonu null değer atanamaz olmalıdır.
  • Yanıtlayanlar koleksiyonu null atanamaz olmalıdır.

Kodu yazarken, başvurular için varsayılan olarak null atanamaz bir başvuru türünün s'ye NullReferenceExceptionyol açabilecek yaygın hatalardan kaçındığını görürsünüz. Bu öğreticiden bir ders, hangi değişkenlerin olabileceği veya olamadığıyla ilgili kararlar vermiş olmanızdır null. Dil, bu kararları ifade etmek için söz dizimi sağlamadı. Şimdi öyle.

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ıtlayan kişiler.
  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. Bir anket sorusunu ve anket çalıştırmasını 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 metni ve soru türü için özellikler 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; }
    }
}

'yi başlatmadığınız QuestionTextiçin, derleyici null atanamayan bir özelliğin başlatılmadığını belirten bir uyarı döndürür. Tasarımınız soru metninin null olmayan olmasını gerektirdiğinden, bunu ve QuestionType değeri başlatmak için bir oluşturucu 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 bağımsız değişkeni de boş değer atanamayan bir başvuru türüdür, bu nedenle derleyici herhangi bir uyarı vermez.

Ardından adlı SurveyRunbir public sınıf oluşturun. Bu sınıf, aşağıdaki kodda gösterildiği gibi ankete soru eklemek için nesnelerin ve yöntemlerin listesini SurveyQuestion 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. İkinci aşırı yüklemesinde AddQuestion null denetimi yoktur çünkü bunlar gerekli değildir: Bu değişkenin null atanamaz olduğunu bildirmişsinizdir. Değeri olamaz null.

Düzenleyicinizde Program.cs dosyasına geçin ve içeriğini Main 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 atanabilir ek açıklama bağlamını etkinleştirdiğinden, boş değer atanamayan bir başvuru türü bekleyen herhangi bir yönteme geçtiğinizde null uyarılar alırsınız. aşağıdaki satırı 'a Mainekleyerek deneyin:

surveyRun.AddQuestion(QuestionType.Text, default);

Yanıtlayanlar oluşturma ve ankete yanıtlar alma

Ardından, anketin yanıtlarını 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 etti.
  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. Yeterli yanıtlayan anketi 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. Null atanabilir desteği etkinleştirin. Id Aşağıdaki kodda gösterildiği gibi bir özellik ve onu 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 static kimlik oluşturarak yeni katılımcılar oluşturmak için bir yöntem 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 vermiyorsa eksik (veya null) bir yanıt döndür.
  2. Her soruyu sorun ve yanıtı kaydedin. Her yanıt da eksik (veya null) olabilir.

Sınıfınıza SurveyResponse 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 depolama alanı null olabileceğini belirten bir Dictionary<int, string>?değeridir. Tasarım amacınızı hem derleyiciye hem de kodunuzu daha sonra okuyan herkese bildirmek için yeni dil özelliğini kullanıyorsunuz. Önce değeri denetlemeden null başvuruyu surveyResponses geri alırsanız bir derleyici uyarısı alırsınız. Derleyici değişkenin AnswerSurvey yukarıdaki null olmayan bir değere ayarlandığını belirleyebildiğinden yönteminde surveyResponses uyarı almazsınız.

null Eksik yanıtlar için kullanılması null atanabilir başvuru türleriyle çalışmanın önemli bir noktasını vurgular: amacınız programınızdaki tüm null değerleri 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ğer, bu eksik değerleri ifade etmenin net bir yoludur. Tüm null değerleri kaldırmaya çalışmak, eksik değerleri olmadan nullifade etmenin başka bir yolunun tanımlanmasına neden olur.

Ardından, sınıfına PerformSurvey yöntemini SurveyRun yazmanız gerekir. Sınıfına aşağıdaki kodu SurveyRun 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 değer atanabilir List<SurveyResponse>? seçeneğiniz yanıtın null olabileceğini gösterir. Bu, anketin henüz yanıtlayanlara verilmediğini gösterir. Yeterli izin verene kadar yanıtlayanların eklendiğine dikkat edin.

Anketi çalıştırmanın son adımı, yönteminin sonunda Main 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. Sınıfına aşağıdaki iki ifade gövdeli üyeyi SurveyResponse 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 kaldırmadan önce null denetimler gereklidir. Answer yöntemi null atanamayan bir dize döndürür, bu nedenle null birleşim işlecini kullanarak eksik yanıt durumunu ele alacağız.

Ardından, bu üç ifade gövdeli üyeyi sınıfına SurveyRun ekleyin:

public IEnumerable<SurveyResponse> AllParticipants => (respondents ?? Enumerable.Empty<SurveyResponse>());
public ICollection<SurveyQuestion> Questions => surveyQuestions;
public SurveyQuestion GetQuestion(int index) => surveyQuestions[index];

Üye değişkenin AllParticipantsrespondents null olabileceğini hesaba katmalıdır, ancak dönüş değeri null olamaz. Bu ifadeyi ve sonrasındaki boş diziyi ?? kaldırarak değiştirirseniz, derleyici sizi yöntemin döndürebileceği null ve dönüş imzası null atanamayan bir tür döndüreceği konusunda uyarır.

Son olarak, yönteminin en altına Main aşağıdaki döngüsü ekleyin:

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");
    }
}

Temel arabirimleri tümünün null atanamaz başvuru türleri döndürmesi için tasarladığınız için bu kodda herhangi bir null denetime ihtiyacınız yoktur.

Kodu alma

Tamamlanmış öğreticinin kodunu csharp/NullableIntroduction klasöründeki örnek depomuzdan alabilirsiniz.

Null atanabilir ve null atanamayan başvuru türleri arasında tür bildirimlerini değiştirerek denemeler yapın. Yanlışlıkla nullbir başvuruyu kaldırmadığınızdan emin olmak için bunun nasıl farklı uyarılar oluşturduğunu görün.

Sonraki adımlar

Entity Framework kullanırken null atanabilir başvuru türünü kullanmayı öğrenin: