Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Tip
Baru mengenal tipe referensi yang dapat bernilai null? Baca Jenis referensi nullable terlebih dahulu. Tutorial ini mengasumsikan bahwa Anda memahami perbedaan antara tipe referensi non-nullable dan nullable serta cara kompilator melacak status null.
Berasal dari bahasa lain? Jika Anda pernah menggunakan tipe nullabel Kotlin, strictNullChecks TypeScript, atau optional di Swift, model konseptualnya sesuai secara langsung. Latihan di sini adalah tentang mengekspresikan niat desain, tidak mempelajari sintaks.
Dalam tutorial ini, Anda membangun pustaka kecil yang memodelkan menjalankan survei. Data memiliki dua pola berbeda yang jenis referensi nullable memungkinkan Anda membedakan:
-
Pertanyaan survei harus selalu ada. Daftar pertanyaan dan teks setiap pertanyaan tidak akan pernah
null. - Respons terhadap pertanyaan mungkin hilang. Responden dapat menolak untuk menjawab beberapa atau semua pertanyaan, dan model harus membuat itu eksplisit.
Anda mendeklarasikan aturan tersebut dengan tipe referensi non-nullable dan nullable. Pengkompilasi kemudian memperingatkan setiap kali perilaku kode tidak cocok dengan desain.
Di tutorial ini, Anda akan:
- Buat aplikasi.
- Buat pertanyaan survei.
- Buat survei pertanyaan.
- Uji persyaratan non-null.
- Jenis respons build.
- Buat responden.
- Hasilkan satu respons survei.
- Buat sekumpulan tanggapan survei.
- Periksa hasil survei.
Tiga kelas memodelkan survei:
-
SurveyQuestion: satu pertanyaan. Teks dan jenis pertanyaan wajib diisi. -
SurveyRun: kumpulan pertanyaan ditambah daftar responden. -
SurveyResponse: satu jawaban responden, yang mungkin hilang.
Setiap jenis menggunakan jenis referensi yang tidak dapat diubah ke null untuk nilai yang diperlukan dan jenis referensi nullable untuk nilai yang hilang.
Prasyarat
Tutorial ini mengasumsikan Anda terbiasa dengan C# dan baik Visual Studio atau CLI .NET.
Membuat aplikasi dan mengaktifkan jenis referensi nullable
Buat aplikasi konsol baru bernama NullableIntroduction:
dotnet new console -n NullableIntroduction
cd NullableIntroduction
Membangun pertanyaan survei
Tambahkan file baru bernama SurveyQuestion.cs ke proyek, dan ganti kontennya dengan kode berikut. Teks dan jenis pertanyaan tidak dapat diubah ke null, sehingga konstruktor harus menginisialisasi keduanya:
namespace NullableIntroduction;
public enum QuestionType
{
YesNo,
Number,
Text
}
public class SurveyQuestion(QuestionType typeOfQuestion, string text)
{
public string QuestionText { get; } = text;
public QuestionType TypeOfQuestion { get; } = typeOfQuestion;
}
Parameter konstruktor adalah jenis referensi yang tidak dapat diubah ke null, sehingga pengkompilasi memperingatkan pemanggil jika salah satu argumen mungkin .null
Buat survei berisi pertanyaan
Selanjutnya, tambahkan file baru bernama SurveyRun.cs ke proyek dan tentukan SurveyRun kelas untuk menyimpan daftar pertanyaan:
namespace NullableIntroduction;
public class SurveyRun
{
private List<SurveyQuestion> surveyQuestions = [];
public void AddQuestion(QuestionType type, string question) =>
AddQuestion(new SurveyQuestion(type, question));
public void AddQuestion(SurveyQuestion surveyQuestion) =>
surveyQuestions.Add(surveyQuestion);
}
Bidang surveyQuestions adalah List<SurveyQuestion> yang tidak boleh bernilai null. Ini menggunakan ekspresi koleksi untuk menginisialisasi daftar kosong. Kedua overload AddQuestion menerima parameter non-nullable, sehingga kompilator memastikan bahwa pemanggil tidak meneruskan null.
Di Program.cs, buat SurveyRun dan tambahkan tiga pertanyaan:
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?");
Uji persyaratan non-null
Untuk melihat bagaimana kompilator memberlakukan parameter yang tidak dapat diubah ke null, coba tambahkan baris berikut dan bangun ulang:
surveyRun.AddQuestion(QuestionType.Text, default);
Kompilator mengeluarkan peringatan CS8625 karena default dievaluasi menjadi null untuk jenis referensi, dan AddQuestion mengharapkan string yang tidak menerima null. Hapus baris sebelum melanjutkan.
Jenis respons build
Responden dapat menolak untuk mengambil survei, dan bahkan ketika mereka berpartisipasi, mereka dapat melewati pertanyaan individual. Kedua bentuk "hilang" adalah hasil yang valid, dan sistem jenis harus membuatnya terlihat. Anda mengekspresikan kedua formulir dengan null.
Tambahkan file baru bernama SurveyResponse.cs ke proyek dan tentukan SurveyResponse kelas. Gunakan konstruktor utama (parameter yang dideklarasikan pada tipe itu sendiri, tersedia di seluruh isi tipe) untuk menyimpan Id yang selalu diperlukan:
namespace NullableIntroduction;
public class SurveyResponse(int id)
{
public int Id { get; } = id;
}
Buat responden
Tambahkan metode pabrik statis (static metode yang membuat dan mengembalikan instans baru dari tipe tersebut, sebagai alternatif untuk memanggil konstruktor secara langsung) yang membuat responden dengan ID acak:
private static readonly Random randomGenerator = new Random();
public static SurveyResponse GetRandomId() => new SurveyResponse(randomGenerator.Next());
Hasilkan satu respons survei
Selanjutnya, tambahkan metode yang meminta survei ke responden. Simpan jawaban dalam kamus yang dapat bernilai null sehingga tipe itu sendiri menunjukkan bahwa responden mungkin menolak menjawab:
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!";
}
}
Kolom surveyResponses adalah Dictionary<int, string>?. Jika Anda mendereferensikan bidang tanpa terlebih dahulu memeriksa null, pengkompilasi mengeluarkan peringatan. Di dalam AnswerSurvey, pengkompilasi melacak bahwa surveyResponsestidak null segera setelah ekspresi new, sehingga badan perulangan tidak memerlukan pemeriksaan tambahan.
Membangun serangkaian respons survei
Tambahkan metode pada SurveyRun yang menyusun daftar responden hingga cukup banyak yang menyetujui untuk berpartisipasi:
private List<SurveyResponse>? respondents;
public void PerformSurvey(int numberOfRespondents)
{
int respondentsConsenting = 0;
respondents = [];
while (respondentsConsenting < numberOfRespondents)
{
var respondent = SurveyResponse.GetRandomId();
if (respondent.AnswerSurvey(surveyQuestions))
respondentsConsenting++;
respondents.Add(respondent);
}
}
Kolom respondents adalah List<SurveyResponse>? - null hingga survei dijalankan.
Hubungi PerformSurvey dari Main:
surveyRun.PerformSurvey(50);
Memeriksa hasil survei
Untuk melaporkan hasil, tampilkan beberapa fungsi bantu dari SurveyResponse dan SurveyRun. Pada SurveyResponse, tambahkan anggota berbadan ekspresi (anggota yang didefinisikan dengan => dan satu ekspresi alih-alih blok { ... }) yang menangani kamus nullable:
public bool AnsweredSurvey => surveyResponses != null;
public string Answer(int index) => surveyResponses?.GetValueOrDefault(index) ?? "No answer";
AnsweredSurvey memeriksa kolom berdasarkan null.
Answer menggunakan ?. operator null-conditional (yang mengevaluasi ke null ketika sisi kiri adalah null alih-alih melempar pengecualian) untuk melakukan dereferensi dengan aman, dan ?? operator null-coalescing (yang menggantikan dengan operand kanan saat operand kiri adalah null) untuk menyediakan nilai cadangan non-null. Tipe nilai balik metode bersifat non-nullable string, sehingga pemanggil tidak memerlukan pengecekan null.
Pada SurveyRun, tambahkan anggota berbadan ekspresi yang menyediakan daftar peserta dan pertanyaan:
public IEnumerable<SurveyResponse> AllParticipants => (respondents ?? Enumerable.Empty<SurveyResponse>());
public ICollection<SurveyQuestion> Questions => surveyQuestions;
public SurveyQuestion GetQuestion(int index) => surveyQuestions[index];
AllParticipants mengembalikan urutan yang tidak dapat diubah ke null meskipun respondents mungkin null. Operator ?? menggantikan Enumerable.Empty<SurveyResponse>() saat bidang belum diisi. Jika Anda menghapus klausa ??, kompilator akan memperingatkan bahwa metode tersebut mungkin mengembalikan null meskipun tipe nilai kembalinya non-nullable.
Terakhir, tulis laporan di bagian Mainbawah :
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");
}
}
Perhatikan bahwa tidak ada pemeriksaan null yang diperlukan untuk participant, , surveyRun.Questionsatau surveyRun.GetQuestion(i). Jenis mendeklarasikan nilai-nilai tersebut sebagai tidak dapat diubah ke null, sehingga pengkompilasi memperlakukannya sebagai tidak null di seluruh perulangan.
Jalankan aplikasi:
dotnet run
Outputnya berbeda setiap kali dijalankan karena responden dihasilkan secara acak, tetapi setiap baris berisi jawaban seorang peserta atau mencatat bahwa mereka menolak.
Kesimpulan
Sampel yang sudah selesai ada di folder csharp/NullableIntroduction dari repositori dotnet/samples . Cobalah mengubah tipe antara nullable dan non-nullable. Menghapus ? dalam desain yang mengizinkan nilai yang tidak ada akan menghasilkan peringatan kompilator yang menunjukkan setiap tempat di mana ketiadaan nilai tersebut berpengaruh.