Jenis referensi yang dapat bernilai null
jenis referensi Nullable adalah sekelompok fitur yang meminimalkan kemungkinan kode Anda menyebabkan runtime untuk melemparkan System.NullReferenceException. Tiga fitur yang membantu Anda menghindari pengecualian ini, termasuk kemampuan untuk secara eksplisit menandai jenis referensi sebagai nullable:
- Penyempurnaan analisis aliran statis yang menentukan apakah variabel mungkin
null
sebelum dilakukan dereferensi. - Atribut yang membuat anotasi API sehingga analisis alur menentukan status null.
- Anotasi variabel yang digunakan pengembang untuk secara eksplisit mendeklarasikan status null yang dimaksudkan untuk variabel.
Pengkompilasi melacak status null setiap ekspresi dalam kode Anda pada waktu kompilasi. Keadaan null memiliki salah satu dari dua nilai:
-
not-null: Ekspresi diketahui tidak-
null
. -
mungkin-null: Ekspresinya mungkin
null
.
Anotasi variabel menentukan ketidaknullan variabel jenis referensi.
-
tidak dapat bernilai null: Jika Anda menetapkan
null
nilai atau ekspresi yang mungkin null ke variabel, pengkompilasi mengeluarkan peringatan. Variabel yang non-nullable memiliki status null bawaan tidak-null. -
nullable: Anda dapat menetapkan
null
nilai atau ekspresi mungkin-null ke variabel. Ketika status null dari variabel adalah mungkin-null, kompilator mengeluarkan peringatan jika Anda mendereferensikan variabel. Status null default untuk variabel adalah mungkin-null.
Sisa artikel ini menjelaskan cara kerja ketiga area fitur tersebut untuk menghasilkan peringatan ketika kode Anda mungkin dereferensi nilai null
. Mendereferensikan variabel berarti mengakses salah satu anggotanya menggunakan operator .
(titik), seperti yang ditunjukkan dalam contoh berikut:
string message = "Hello, World!";
int length = message.Length; // dereferencing "message"
Ketika Anda mendereferensikan variabel yang nilainya adalah null
, runtime melempar System.NullReferenceException.
Peringatan serupa dapat dihasilkan ketika []
notasi digunakan untuk mengakses anggota objek ketika objek adalah null
:
using System;
public class Collection<T>
{
private T[] array = new T[100];
public T this[int index]
{
get => array[index];
set => array[index] = value;
}
}
public static void Main()
{
Collection<int> c = default;
c[10] = 1; // CS8602: Possible dereference of null
}
Anda akan mempelajari tentang:
- Analisis kondisi null pengkompilasi: bagaimana pengkompilasi menentukan apakah ekspresi bukan null, atau mungkin null.
- Atribut-atribut yang diterapkan pada API yang menyediakan lebih banyak konteks untuk analisis status null kompilator.
- Anotasi variabel nullable yang memberikan informasi tentang maksud Anda terhadap variabel. Anotasi berguna untuk bidang, parameter, dan nilai pengembalian untuk mengatur status null default.
- Aturan yang mengatur argumen jenis generik. Batasan baru ditambahkan karena parameter jenis dapat berupa jenis referensi atau jenis nilai. Akhiran
?
diimplementasikan secara berbeda untuk tipe nilai nullable dan tipe referensi nullable. - Konteks Nullable dapat membantu Anda memindahkan proyek besar. Anda dapat mengaktifkan peringatan dan anotasi dalam konteks null di sebagian bagian dari aplikasi Anda saat melakukan migrasi. Setelah mengatasi lebih banyak peringatan, Anda dapat mengaktifkan kedua pengaturan untuk seluruh proyek.
Terakhir, Anda mempelajari perangkap umum yang diketahui dalam analisis keadaan null untuk jenis dan array struct
.
Anda juga dapat menjelajahi konsep-konsep ini dalam modul Learn kami tentang keamanan Nullable di C#.
Analisis kondisi null
Analisis keadaan null melacak keadaan null referensi. Ekspresi adalah bukan-null atau mungkin null. Kompilator menentukan bahwa variabel tidak null dalam dua cara:
- Variabel diberi nilai yang diketahui tidak null.
- Variabel diperiksa terhadap
null
dan tidak ditetapkan sejak pemeriksaan itu.
Variabel apa pun yang tidak dapat ditentukan pengkompilasi sebagai tidak-null dianggap mungkin-null. Analisis ini memberikan peringatan dalam situasi di mana Anda mungkin secara tidak sengaja mendereferensikan null
nilai. Kompilator menghasilkan peringatan berdasarkan status null.
- Ketika variabel non-null, variabel tersebut dapat didereferensikan dengan aman.
- Ketika variabel mungkin null, variabel tersebut harus diperiksa untuk memastikan bahwa variabel tersebut tidak
null
sebelum mendereferensikannya.
Pertimbangkan contoh berikut:
string? message = null;
// warning: dereference null.
Console.WriteLine($"The length of the message is {message.Length}");
var originalMessage = message;
message = "Hello, World!";
// No warning. Analysis determined "message" is not-null.
Console.WriteLine($"The length of the message is {message.Length}");
// warning!
Console.WriteLine(originalMessage.Length);
Dalam contoh sebelumnya, kompilator menentukan bahwa message
adalah mungkin null ketika pesan pertama dicetak. Tidak ada peringatan untuk pesan kedua. Baris akhir kode menghasilkan peringatan karena originalMessage
mungkin null. Contoh berikut menunjukkan penggunaan yang lebih praktis untuk melalui pohon simpul hingga ke akar, memproses setiap simpul selama menjelajah.
void FindRoot(Node node, Action<Node> processNode)
{
for (var current = node; current != null; current = current.Parent)
{
processNode(current);
}
}
Kode sebelumnya tidak menghasilkan peringatan apa pun untuk mendereferensi variabel current
. Analisis statis menentukan bahwa current
tidak pernah didereferensikan ketika mungkin null. Variabel current
diperiksa terhadap null
sebelum current.Parent
diakses, dan sebelum meneruskan current
ke tindakan ProcessNode
. Contoh sebelumnya menunjukkan bagaimana kompilator menentukan status null untuk variabel lokal saat diinisialisasi, ditetapkan, atau dibandingkan dengan null
.
Analisis status null tidak menelusuri ke dalam metode yang dipanggil. Akibatnya, bidang yang diinisialisasi dalam metode pembantu umum yang disebut oleh semua konstruktor mungkin menghasilkan peringatan dengan pesan berikut:
Properti 'nama' yang tidak dapat diubah ke null harus berisi nilai tidak null saat keluar dari konstruktor.
Anda dapat mengatasi peringatan ini dengan salah satu dari dua cara: dengan Penautan Konstruktor, atau atribut yang dapat bernilai nol pada metode pembantu. Kode berikut menunjukkan contoh masing-masing. Kelas Person
menggunakan konstruktor umum yang dipanggil oleh semua konstruktor lain. Kelas Student
ini memiliki metode pembantu yang beranotasi dengan atribut System.Diagnostics.CodeAnalysis.MemberNotNullAttribute:
using System.Diagnostics.CodeAnalysis;
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Person(string firstName, string lastName)
{
FirstName = firstName;
LastName = lastName;
}
public Person() : this("John", "Doe") { }
}
public class Student : Person
{
public string Major { get; set; }
public Student(string firstName, string lastName, string major)
: base(firstName, lastName)
{
SetMajor(major);
}
public Student(string firstName, string lastName) :
base(firstName, lastName)
{
SetMajor();
}
public Student()
{
SetMajor();
}
[MemberNotNull(nameof(Major))]
private void SetMajor(string? major = default)
{
Major = major ?? "Undeclared";
}
}
Analisis status yang dapat diubah ke null dan peringatan yang dihasilkan kompilator membantu Anda menghindari kesalahan program dengan mendereferensikan null
. Artikel tentang mengatasi peringatan nullable menyediakan teknik untuk mengoreksi peringatan yang kemungkinan besar terlihat dalam kode Anda. Diagnostik yang dihasilkan dari analisis keadaan null bersifat hanya sebagai peringatan.
Atribut pada tanda tangan API
Analisis status null membutuhkan petunjuk dari pengembang untuk memahami semantik API. Beberapa API memberikan pemeriksaan null, dan harus mengubah status null variabel dari mungkin null menjadi tidak null. API lain mengembalikan ekspresi yang tidak null atau mungkin null tergantung pada status null argumen input. Misalnya, pertimbangkan kode berikut yang menampilkan pesan dalam huruf besar:
void PrintMessageUpper(string? message)
{
if (!IsNull(message))
{
Console.WriteLine($"{DateTime.Now}: {message.ToUpper()}");
}
}
bool IsNull(string? s) => s == null;
Berdasarkan inspeksi, setiap pengembang akan menganggap kode ini aman, dan tidak boleh menghasilkan peringatan. Namun kompilator tidak tahu bahwa IsNull
menyediakan pemeriksaan null dan mengeluarkan peringatan untuk pernyataan message.ToUpper()
, menganggap message
sebagai variabel yang kemungkinan null.
NotNullWhen
Gunakan atribut untuk memperbaiki peringatan ini:
bool IsNull([NotNullWhen(false)] string? s) => s == null;
Atribut ini menginformasikan pengkompilasi, bahwa, jika IsNull
mengembalikan false
, parameternya s
tidak null. Pengkompilasi mengubah null-state dari message
menjadi not-null di dalam blok if (!IsNull(message)) {...}
. Tidak ada peringatan yang dikeluarkan.
Atribut memberikan informasi terperinci tentang status null argumen, nilai pengembalian, dan anggota instans objek yang digunakan untuk memanggil anggota. Detail pada setiap atribut dapat ditemukan di artikel referensi bahasa pada atribut referensi yang dapat diubah ke null. Pada .NET 5, semua API runtime .NET dianotasi. Anda meningkatkan analisis statis dengan menganotasi API Anda untuk memberikan informasi semantik tentang status null argumen dan mengembalikan nilai.
Anotasi variabel yang dapat diubah ke null
Analisis kondisi null menyediakan analisis yang kuat untuk variabel lokal. Kompilator membutuhkan informasi lebih lanjut dari Anda untuk variabel anggota. Pengompilasi memerlukan informasi lebih lanjut untuk mengatur keadaan null dari semua bidang pada kurung buka dari anggota. Salah satu konstruktor yang dapat diakses dapat digunakan untuk menginisialisasi objek. Jika bidang anggota mungkin pernah diatur ke null
, kompilator harus mengasumsikan status null-nya adalah mungkin null di awal setiap metode.
Anda menggunakan anotasi yang dapat mendeklarasikan apakah variabel adalah jenis referensi yang dapat bernilai null atau jenis referensi yang tidak dapat bernilai null. Anotasi ini membuat pernyataan penting tentang status null untuk variabel:
-
Referensi tidak seharusnya null. Status default variabel referensi yang tidak dapat diubah ke null bukan nol. Kompilator memberlakukan aturan yang memastikan aman untuk mendereferensikan variabel ini tanpa terlebih dahulu memeriksa bahwa variabel tersebut bukan null:
- Variabel harus diinisialisasi ke nilai tidak null.
- Variabel tidak pernah dapat ditetapkan nilainya
null
. Kompilator mengeluarkan peringatan ketika kode menetapkan ekspresi mungkin null ke variabel yang seharusnya tidak null.
-
Referensi mungkin null. Status default variabel referensi nullable adalah mungkin null. Pengkompilasi memberlakukan aturan untuk memastikan bahwa Anda memeriksa
null
referensi dengan benar:- Variabel hanya dapat didereferensikan ketika pengkompilasi dapat menjamin bahwa nilainya tidak
null
. - Variabel ini dapat diinisialisasi dengan nilai
null
default dan dapat ditetapkan nilainull
dalam kode lain. - Pengkompilasi tidak mengeluarkan peringatan saat kode menetapkan ekspresi mungkin-null ke variabel yang mungkin null.
- Variabel hanya dapat didereferensikan ketika pengkompilasi dapat menjamin bahwa nilainya tidak
Setiap variabel referensi yang tidak dapat bernilai null memiliki status null awal dari tidak null. Variabel referensi nullable memiliki status null awal
Jenis referensi yang dapat diubah ke null dicatat menggunakan sintaks yang sama dengan tipe nilai yang dapat diubah ke null: ?
ditambahkan ke jenis variabel. Misalnya, deklarasi variabel berikut mewakili variabel string yang dapat diubah ke null, name
:
string? name;
Ketika jenis referensi nullable diaktifkan, variabel apa pun di mana ?
tidak ditambahkan ke nama jenis adalah jenis referensi non-nullable. Itu termasuk semua variabel tipe referensi dalam kode yang ada begitu Anda mengaktifkan fitur ini. Namun, variabel lokal yang diketik secara implisit (dinyatakan menggunakan var
) adalah jenis referensi yang dapat diubah ke null. Seperti yang ditunjukkan bagian sebelumnya, analisis statis menentukan status null variabel lokal untuk menentukan apakah variabel tersebut mungkin-null sebelum mendereferensikannya.
Terkadang Anda harus mengambil alih peringatan ketika Anda tahu variabel tidak null, tetapi kompilator menentukan status null-nya adalah mungkin null. Anda menggunakan operator null-forgiving!
setelah nama variabel untuk memaksa status null dinilai sebagai tidak-null. Misalnya, jika Anda tahu name
variabelnya bukan null
tetapi kompilator mengeluarkan peringatan, Anda dapat menulis kode berikut untuk mengambil alih analisis kompilator:
name!.Length;
Jenis referensi nullable dan jenis nilai nullable menyediakan konsep semantik serupa: Variabel dapat mewakili nilai atau objek, atau variabel tersebut mungkin null
. Namun, jenis referensi yang dapat diubah ke null dan jenis nilai yang dapat diubah ke null diimplementasikan secara berbeda: jenis nilai yang dapat diubah ke null diimplementasikan menggunakan System.Nullable<T>, dan jenis referensi null diimplementasikan oleh atribut yang dibaca oleh kompilator. Misalnya, string?
dan string
keduanya diwakili oleh jenis yang sama: System.String. Namun, int?
dan int
masing-masing diwakili oleh System.Nullable<System.Int32>
dan System.Int32.
Jenis referensi yang dapat diubah ke null adalah fitur waktu kompilasi. Itu berarti dimungkinkan bagi penelepon untuk mengabaikan peringatan, dengan sengaja menggunakan null
sebagai argumen untuk metode yang mengharapkan referensi yang tidak dapat diubah ke null. Penulis pustaka harus menyertakan pemeriksaan run-time terhadap nilai argumen null.
ArgumentNullException.ThrowIfNull adalah opsi yang disukai untuk memeriksa parameter terhadap null pada waktu berjalan. Selain itu, perilaku runtime dari program yang menggunakan anotasi nullable akan tetap sama apabila semua anotasi nullable, yaitu (?
dan !
), dihapus. Satu-satunya tujuan mereka adalah mengekspresikan niat desain dan memberikan informasi untuk analisis status null.
Penting
Menggunakan anotasi null dapat mengubah cara Entity Framework Core menentukan apakah anggota data diperlukan. Anda dapat mempelajari detail selengkapnya dalam artikel tentang Dasar-Dasar Inti Entity Framework: Bekerja dengan Jenis Referensi Yang Dapat Diubah Ke null.
Generik
Generik memerlukan aturan terperinci guna menangani T?
untuk parameter T
jenis apa pun. Aturan harus terperinci karena sejarah dan implementasi yang berbeda untuk jenis nilai nullable dan jenis referensi nullable.
Jenis nilai yang dapat diubah ke null diimplementasikan menggunakan struktur System.Nullable<T>.
Jenis referensi yang dapat diubah ke null diimplementasikan sebagai anotasi jenis yang menyediakan aturan semantik kepada kompilator.
- Jika argumen jenis untuk
T
adalah jenis referensi,T?
mereferensikan jenis referensi nullable yang sesuai. Misalnya, jikaT
adalahstring
, makaT?
adalahstring?
. - Jika argumen jenis untuk
T
adalah jenis nilai,T?
mereferensikan jenis nilai yang sama,T
. Misalnya, jikaT
adalahint
, makaT?
juga merupakanint
. - Jika argumen tipe untuk
T
adalah tipe referensi nullable,T?
mereferensikan tipe referensi nullable yang sama. Misalnya, jikaT
adalahstring?
, makaT?
juga merupakanstring?
. - Jika argumen jenis untuk
T
adalah jenis nilai yang dapat bernilai null,T?
mereferensikan jenis nilai yang dapat bernilai null yang sama. Misalnya, jikaT
adalahint?
, makaT?
juga merupakanint?
.
Untuk nilai yang dikembalikan, T?
setara dengan [MaybeNull]T
; untuk nilai argumen, T?
setara dengan [AllowNull]T
. Untuk informasi selengkapnya, lihat artikel tentang Atribut untuk analisis status nol dalam referensi bahasa.
Anda dapat menentukan perilaku yang berbeda menggunakan batasan:
- Batasan
class
berarti bahwaT
harus merupakan jenis referensi yang tidak dapat diubah ke null (misalnyastring
). Kompilator menghasilkan peringatan jika Anda menggunakan jenis referensi yang dapat diubah ke null, sepertistring?
untukT
. - Batasan
class?
berarti bahwaT
harus merupakan jenis referensi, baik yang tidak dapat diubah ke null (string
) atau jenis referensi yang dapat diubah ke null (misalnyastring?
). Ketika parameter jenis adalah tipe referensi yang bisa diubah menjadi null, sepertistring?
, sebuah ekspresi dariT?
merujuk pada tipe referensi bisa null yang sama, sepertistring?
. - Batasan
notnull
berarti bahwaT
harus merupakan jenis referensi yang tidak dapat diubah ke null, atau jenis nilai yang tidak dapat diubah ke null. Jika Anda menggunakan referensi yang dapat bernilai null atau nilai yang dapat bernilai null untuk parameter jenis, kompilator akan menghasilkan peringatan. Selain itu, ketikaT
adalah tipe nilai, nilai yang dikembalikan adalah tipe nilai tersebut, bukan tipe nilai nullable yang sesuai.
Batasan ini membantu memberikan informasi lebih lanjut kepada pengkompilasi tentang cara T
digunakan. Itu membantu ketika pengembang memilih tipe untuk T
dan memberikan analisis status null yang lebih baik saat sebuah instans dari tipe generik digunakan.
Konteks dapat bernilai null
Konteks nullable menentukan bagaimana anotasi jenis referensi null ditangani dan peringatan apa yang dihasilkan oleh analisis status null statis. Konteks nullable berisi dua penanda: pengaturan anotasi dan pengaturan peringatan .
Pengaturan anotasi dan peringatan dinonaktifkan secara default untuk proyek yang ada. Mulai dari .NET 6 (C# 10), kedua bendera diaktifkan secara default untuk proyek baru. Alasan adanya dua opsi berbeda untuk pengaturan konteks nullable adalah untuk mempermudah migrasi proyek besar yang sudah ada sebelum pengenalan tipe referensi nullable.
Untuk proyek kecil, Anda dapat mengaktifkan jenis referensi nullable, memperbaiki peringatan, dan melanjutkan. Namun, untuk proyek yang lebih besar dan solusi multi-proyek, ini mungkin menghasilkan sejumlah besar peringatan. Anda dapat menggunakan pragmas untuk mengaktifkan jenis referensi yang dapat bernilai null per file saat Anda mulai menggunakannya. Fitur baru yang melindungi dari penggunaan System.NullReferenceException dapat mengganggu saat diaktifkan di basis kode yang ada.
- Semua variabel referensi yang diketik secara eksplisit ditafsirkan sebagai jenis referensi yang tidak dapat diubah ke null.
- Arti batasan
class
dalam generik berubah menjadi berarti jenis referensi yang tidak dapat diubah ke null. - Peringatan baru dihasilkan karena aturan baru ini.
Konteks anotasi yang dapat diubah ke null menentukan perilaku kompilator. Ada empat kombinasi untuk konteks pengaturan null:
-
keduanya dinonaktifkan: Kodenya nullable-oblivious.
Nonaktifkan mencocokkan perilaku sebelum tipe referensi null diaktifkan; kecuali sintaks baru menghasilkan peringatan alih-alih kesalahan.
- Peringatan nullable dinonaktifkan.
- Semua variabel jenis referensi adalah jenis referensi yang dapat diubah ke null.
- Penggunaan akhiran
?
untuk mendeklarasikan jenis referensi yang dapat diubah ke null menghasilkan peringatan. - Anda dapat menggunakan operator pengampunan null,
!
, tetapi tidak berpengaruh.
-
keduanya diaktifkan: Pengompilasi mengaktifkan semua analisis referensi null dan seluruh fitur bahasa.
- Semua peringatan baru yang dapat diubah ke null diaktifkan.
- Anda dapat menggunakan akhiran
?
untuk mendeklarasikan jenis referensi yang dapat diubah ke null. - Variabel jenis referensi tanpa akhiran
?
adalah jenis referensi yang tidak dapat diubah ke null. - Operator pengampunan null menekan peringatan untuk kemungkinan dereferensi
null
.
-
peringatan diaktifkan: Kompilator melakukan analisis null secara menyeluruh dan menghasilkan peringatan ketika kode mungkin akan mendereferensi
null
.- Semua peringatan baru untuk nilai yang dapat menjadi null diaktifkan.
- Penggunaan akhiran
?
untuk mendeklarasikan jenis referensi yang dapat diubah ke null menghasilkan peringatan. - Semua variabel jenis referensi boleh bernilai null. Namun, anggota memiliki status null dari not null pada kurung kurawal pembuka dari semua metode kecuali dinyatakan dengan akhiran
?
. - Anda dapat menggunakan operator pengampunan null,
!
.
-
Anotasi diaktifkan: Pengompilasi tidak mengeluarkan peringatan ketika kode mungkin melakukan dereferensi
null
, atau saat Anda menetapkan ekspresi mungkin-null ke variabel yang tidak boleh null.- Semua peringatan null baru dinonaktifkan.
- Anda dapat menggunakan akhiran
?
untuk mendeklarasikan jenis referensi yang dapat diubah ke null. - Variabel jenis referensi tanpa akhiran
?
adalah jenis referensi yang tidak dapat diubah ke null. - Anda dapat menggunakan operator pengampunan null,
!
, tetapi tidak berpengaruh.
Konteks anotasi yang dapat diubah ke null dan konteks peringatan yang dapat diubah ke null dapat diatur untuk proyek menggunakan <Nullable>
elemen dalam file .csproj Anda. Elemen ini mengonfigurasi bagaimana kompilator menginterpretasikan ketidaknull-an tipe dan peringatan apa yang dihasilkan. Tabel berikut ini memperlihatkan nilai yang diizinkan dan meringkas konteks yang mereka tentukan.
Konteks | Peringatan dereferensi | Peringatan tugas | Jenis referensi |
? akhiran |
! operator |
---|---|---|---|---|---|
disable |
Nonaktif | Nonaktif | Semua bisa bernilai null | Menghasilkan peringatan | Tidak berpengaruh |
enable |
Diaktifkan | Diaktifkan | Tidak dapat diubah ke null kecuali dinyatakan dengan ? |
Mendeklarasikan tipe yang dapat bernilai null | Menyembunyikan peringatan untuk kemungkinan penugasan null |
warnings |
Diaktifkan | Tidak berlaku | Semua nullable, tetapi anggota dianggap tidak-null saat membuka kurung metode | Menghasilkan peringatan | Menyembunyikan peringatan untuk kemungkinan penugasan null |
annotations |
Nonaktif | Nonaktif | Tidak dapat diubah ke null kecuali dinyatakan dengan ? |
Mendeklarasikan tipe yang dapat bernilai null | Tidak berpengaruh |
Variabel jenis referensi dalam kode yang dikompilasi dalam konteks yang dinonaktifkan adalah nullable-oblivious. Anda dapat menetapkan null
variabel harfiah atau mungkin-null ke variabel yang nullable-oblivious. Namun, status default variabel nullable-oblivious adalah tidak-null.
Anda dapat memilih pengaturan mana yang terbaik untuk proyek Anda:
- Pilih nonaktifkan untuk proyek lama yang tidak ingin Anda perbarui berdasarkan diagnostik atau fitur baru.
- Pilih peringatan untuk menentukan di mana kode Anda mungkin melemparkan System.NullReferenceException. Anda dapat mengatasi peringatan tersebut sebelum memodifikasi kode untuk mengaktifkan jenis referensi yang tidak dapat diubah ke null.
- Pilih anotasi untuk mengekspresikan niat desain Anda sebelum mengaktifkan peringatan.
- Pilih aktifkan untuk proyek baru dan proyek aktif tempat Anda ingin melindungi dari pengecualian referensi null.
Contoh:
<Nullable>enable</Nullable>
Anda juga dapat menggunakan arahan untuk mengatur bendera yang sama ini di mana saja dalam kode sumber Anda. Arahan ini paling berguna saat Anda memigrasikan basis kode besar.
-
#nullable enable
: Mengatur anotasi dan bendera peringatan ke mengaktifkan. -
#nullable disable
: Mengatur anotasi dan bendera peringatan ke menonaktifkan. -
#nullable restore
: Memulihkan bendera anotasi dan bendera peringatan ke pengaturan proyek. -
#nullable disable warnings
: Atur bendera peringatan ke nonaktifkan. -
#nullable enable warnings
: Atur bendera peringatan ke mengaktifkan. -
#nullable restore warnings
: Memulihkan bendera peringatan ke pengaturan proyek. -
#nullable disable annotations
: Atur bendera anotasi ke nonaktifkan. -
#nullable enable annotations
: Atur bendera anotasi ke mengaktifkan. -
#nullable restore annotations
: Memulihkan bendera anotasi ke pengaturan proyek.
Untuk baris kode apa pun, Anda dapat mengatur salah satu kombinasi berikut:
Bendera peringatan | Penanda anotasi | Menggunakan |
---|---|---|
proyek bawaan | pengaturan default proyek | Bawaan |
aktifkan | nonaktifkan | Memperbaiki peringatan analisis |
aktifkan | pengaturan standar proyek | Mengatasi peringatan analisis |
proyek default | aktifkan | Tambahkan anotasi jenis |
aktifkan | aktifkan | Kode sudah dimigrasikan |
nonaktifkan | aktifkan | Melakukan anotasi kode sebelum memperbaiki peringatan |
nonaktifkan | nonaktifkan | Menambahkan kode lama ke proyek yang dimigrasikan |
proyek default | nonaktifkan | Jarang |
nonaktifkan | pengaturan awal proyek | Jarang |
Sembilan kombinasi tersebut memberi Anda kontrol terperinci atas diagnostik yang dikeluarkan kompilator untuk kode Anda. Anda dapat mengaktifkan lebih banyak fitur di area mana pun yang Anda perbarui, tanpa melihat lebih banyak peringatan yang belum siap Anda atasi.
Penting
Konteks nullable global tidak berlaku untuk file kode yang dihasilkan. Dalam kedua strategi, konteks nullable dinonaktifkan untuk file sumber apa pun yang ditandai sebagai digenerate. Ini berarti API apa pun dalam file yang dihasilkan tidak dianotasi. Tidak ada peringatan nullable yang ditampilkan untuk file yang dihasilkan. Ada empat cara file ditandai sebagai dihasilkan:
- Dalam .editorconfig, tentukan
generated_code = true
di bagian yang berlaku untuk file tersebut. - Memasukkan
<auto-generated>
atau<auto-generated/>
pada komentar di bagian atas file. Ini bisa berada di baris mana pun dalam komentar itu, tetapi blok komentar harus menjadi elemen pertama dalam file. - Memulai nama file dengan TemporaryGeneratedFile_
- Mengakhiri nama file dengan .designer.cs, .generated.cs, .g.cs, atau .g.i.cs.
Generator dapat memilih untuk ikut serta dengan menggunakan direktif pra-prosesor #nullable
.
Secara default, anotasi nullable dan bendera peringatan berada dalam kondisi dinonaktifkan. Itu berarti bahwa kode Anda yang ada dikompilasi tanpa perubahan dan tanpa menghasilkan peringatan baru. Dimulai dengan .NET 6, proyek baru menyertakan elemen <Nullable>enable</Nullable>
di semua templat proyek, menetapkan bendera ini ke diaktifkan.
Opsi ini menyediakan dua strategi berbeda untuk memperbarui basis kode yang ada untuk menggunakan jenis referensi yang dapat bernilai null.
Perangkap yang diketahui
Larik dan struktur data yang berisi tipe referensi menjadi hambatan yang dikenal dalam konteks referensi yang dapat bernilai null dan analisis statis yang menentukan keamanan penggunaan null. Dalam kedua situasi, referensi yang tidak dapat diubah ke null mungkin diinisialisasi ke null
, tanpa menghasilkan peringatan.
Struktur
Struktur yang berisi jenis referensi yang tidak dapat diubah ke null memungkinkan penetapan default
untuknya tanpa peringatan apa pun. Pertimbangkan contoh berikut:
using System;
#nullable enable
public struct Student
{
public string FirstName;
public string? MiddleName;
public string LastName;
}
public static class Program
{
public static void PrintStudent(Student student)
{
Console.WriteLine($"First name: {student.FirstName.ToUpper()}");
Console.WriteLine($"Middle name: {student.MiddleName?.ToUpper()}");
Console.WriteLine($"Last name: {student.LastName.ToUpper()}");
}
public static void Main() => PrintStudent(default);
}
Dalam contoh sebelumnya, tidak ada peringatan pada PrintStudent(default)
saat jenis referensi yang tidak dapat diubah ke null FirstName
dan LastName
adalah null.
Kasus lain yang lebih umum adalah ketika Anda berurusan dengan struktur generik. Pertimbangkan contoh berikut:
#nullable enable
public struct S<T>
{
public T Prop { get; set; }
}
public static class Program
{
public static void Main()
{
string s = default(S<string>).Prop;
}
}
Dalam contoh sebelumnya, properti Prop
adalah null
saat waktu proses. Ini ditetapkan ke string yang tidak dapat diubah ke null tanpa peringatan apa pun.
Larik
Array juga merupakan kelemahan umum yang dikenal dalam tipe referensi bernilai null. Pertimbangkan contoh berikut yang tidak menghasilkan peringatan apa pun:
using System;
#nullable enable
public static class Program
{
public static void Main()
{
string[] values = new string[10];
string s = values[0];
Console.WriteLine(s.ToUpper());
}
}
Dalam contoh sebelumnya, deklarasi array menunjukkan ia memegang string yang tidak dapat diubah ke null, sementara elemennya semuanya diinisialisasi ke null
. Kemudian, variabel s
ditetapkan nilai null
(elemen pertama dari array). Akhirnya, variabel s
di-dereference menyebabkan pengecualian runtime.
Konstruktor
Konstruktor kelas akan tetap memanggil finalizer, bahkan ketika ada pengecualian yang dilemparkan oleh konstruktor tersebut.
Contoh berikut menunjukkan perilaku tersebut:
public class A
{
private string _name;
private B _b;
public A(string name)
{
ArgumentNullException.ThrowIfNullOrEmpty(name);
_name = name;
_b = new B();
}
~A()
{
Dispose();
}
public void Dispose()
{
_b.Dispose();
GC.SuppressFinalize(this);
}
}
public class B: IDisposable
{
public void Dispose() { }
}
public void Main()
{
var a = new A(string.Empty);
}
Dalam contoh sebelumnya, System.NullReferenceException akan terlempar ketika _b.Dispose();
dijalankan, jika parameter name
adalah null
. Panggilan ke _b.Dispose();
tidak akan pernah melempar ketika konstruktor berhasil diselesaikan. Namun, tidak ada peringatan yang dikeluarkan oleh pengkompilasi, karena analisis statis tidak dapat menentukan apakah metode (seperti konstruktor) selesai tanpa pengecualian runtime yang dilemparkan.