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.
Dalam konteks yang diaktifkan nullable, compiler melakukan analisis statis kode untuk menentukan status null dari semua variabel jenis referensi:
- not-null: Analisis statis menentukan bahwa variabel memiliki nilai non-null.
- mungkin-null: Analisis statis tidak dapat menentukan bahwa variabel ditetapkan ke nilai non-null.
Status ini memungkinkan pengkompilasi untuk memberikan peringatan ketika Anda mungkin mendereferensikan nilai null, melemparkan System.NullReferenceException. Atribut ini menyediakan pengkompilasi dengan informasi semantik tentang status null argumen, nilai pengembalian, dan anggota objek. Atribut mengklarifikasi status argumen dan mengembalikan nilai. Pengompilasi memberikan peringatan yang lebih akurat ketika API Anda dianomasikan dengan benar dengan informasi semantik ini.
Artikel ini memberi deskripsi singkat tentang setiap atribut jenis referensi yang dapat diubah ke null dan cara menggunakannya.
Mari kita mulai dengan contoh. Bayangkan pustaka Anda memiliki API berikut yang mengambil string sumber daya. Metode ini awalnya dikompilasi dalam konteks terlupakan nullable:
bool TryGetMessage(string key, out string message)
{
if (_messageMap.ContainsKey(key))
message = _messageMap[key];
else
message = null;
return message != null;
}
Contoh sebelumnya mengikuti pola Try* yang akrab di .NET. Ada dua parameter referensi untuk API ini: key dan message. API ini memiliki aturan berikut yang berkaitan dengan status null dari parameter ini:
- Pemanggil tidak boleh meneruskan
nullsebagai argumen untukkey. - Pemanggil dapat meneruskan variabel yang nilainya
nullsebagai argumen untukmessage. - Jika metode
TryGetMessagemengembalikantrue, nilaimessagetidak null. Jika nilai yang dikembalikan adalahfalse, nilainyamessagenull.
Aturan untuk key dapat diekspresikan dengan tepat: key harus merupakan jenis referensi yang tidak dapat diubah ke null. Parameter message lebih kompleks. Ini memungkinkan variabel yang null sebagai argumen, tetapi menjamin, pada keberhasilan, bahwa argumen out bukan null. Untuk skenario ini, Anda memerlukan kosakata yang lebih kaya untuk menggambarkan harapan. Atribut NotNullWhen menjelaskan status null untuk argumen yang digunakan untuk message parameter .
Catatan
Menambahkan atribut ini memberi compiler informasi lebih lanjut tentang aturan untuk API Anda. Saat kode panggilan dikompilasi dalam konteks yang diaktifkan nullable, pengkompilasi memperingatkan pemanggil ketika mereka melanggar aturan tersebut. Atribut ini tidak mengaktifkan lebih banyak pemeriksaan pada implementasi Anda.
| Atribut | Kategori | Makna |
|---|---|---|
| AllowNull | Prasyarat | Parameter, bidang, atau properti yang tidak dapat diubah ke null mungkin null. |
| DisallowNull | Prasyarat | Parameter, bidang, atau properti yang dapat diubah ke null tidak boleh null. |
| MaybeNull | Pascakondisi | Parameter, bidang, properti, atau nilai pengembalian yang tidak dapat diubah ke null mungkin null. |
| NotNull | Pascakondisi | Parameter, bidang, properti, atau nilai yang dapat diubah ke null tidak pernah null. |
| MaybeNullWhen | Pascakondisi bersyarat | Argumen yang tidak dapat diubah ke null mungkin null ketika metode mengembalikan nilai yang ditentukan bool . |
| NotNullWhen | Pascakondisi bersyarat | Argumen nullable tidak null ketika metode mengembalikan nilai yang ditentukan bool . |
| NotNullIfNotNull | Pascakondisi bersyarat | Nilai pengembalian, properti, atau argumen tidak null jika argumen untuk parameter yang ditentukan bukan null. |
| MemberNotNull | Metode dan metode pembantu properti | Anggota yang tercantum tidak null ketika metode kembali. |
| MemberNotNullWhen | Metode dan metode pembantu properti | Anggota yang tercantum tidak null ketika metode mengembalikan nilai yang ditentukan bool . |
| DoesNotReturn | Kode yang tidak dapat dijangkau | Metode atau properti tidak pernah kembali. Dengan kata lain, itu selalu melemparkan pengecualian. |
| DoesNotReturnIf | Kode yang tidak dapat dijangkau | Metode atau properti ini tidak pernah mengembalikan jika parameter bool terkait memiliki nilai yang ditentukan. |
Deskripsi sebelumnya adalah referensi cepat untuk apa yang dilakukan setiap atribut. Bagian berikut menjelaskan perilaku dan arti atribut ini secara lebih menyeluruh.
Prasyarat: AllowNull dan DisallowNull
Pertimbangkan properti baca/tulis yang tidak pernah mengembalikan null karena memiliki nilai default yang wajar. Pemanggil meneruskan null ke aksesor yang ditetapkan saat mengaturnya ke nilai default tersebut. Misalnya, pertimbangkan sistem olahpesan yang meminta nama layar di ruang obrolan. Jika tidak ada yang disediakan, sistem menghasilkan nama acak:
public string ScreenName
{
get => _screenName;
set => _screenName = value ?? GenerateRandomScreenName();
}
private string _screenName;
Saat Anda mengompilasi kode sebelumnya dalam konteks samar-samar, semuanya baik-baik saja. Setelah Anda mengaktifkan jenis referensi nullable, properti ScreenName menjadi referensi yang tidak dapat diubah ke null. Pemanggil tidak perlu memeriksa properti yang dikembalikan untuk null. Tetapi sekarang mengatur properti untuk null menghasilkan peringatan. Untuk mendukung jenis kode ini, Anda menambah System.Diagnostics.CodeAnalysis.AllowNullAttribute atribut ke properti, seperti yang ditunjukkan dalam kode berikut:
[AllowNull]
public string ScreenName
{
get => _screenName;
set => _screenName = value ?? GenerateRandomScreenName();
}
private string _screenName = GenerateRandomScreenName();
Anda mungkin perlu menambahkan using arahan untuk System.Diagnostics.CodeAnalysis menggunakan atribut ini dan atribut lain yang dibahas dalam artikel ini. Atribut diterapkan ke properti, bukan aksesor set. Atribut AllowNull menentukan pra-kondisi, dan hanya berlaku untuk argumen. Aksesor get memiliki nilai pengembalian, tetapi tidak ada parameter. Oleh karena itu, atribut AllowNull hanya berlaku untuk aksesor set.
Contoh sebelumnya menunjukkan apa yang harus dicari saat menambahkan atribut AllowNull pada argumen:
- Kontrak umum untuk variabel tersebut adalah bahwa seharusnya tidak
null, jadi Anda menginginkan jenis referensi yang tidak dapat diubah ke null. - Ada skenario bagi pemanggil untuk meneruskan
nullsebagai argumen, meskipun bukan penggunaan yang paling umum.
Paling sering Anda memerlukan atribut ini untuk properti, atau in, out, dan ref argumen. Atribut AllowNull adalah pilihan terbaik saat variabel biasanya non-null, tetapi Anda perlu mengizinkan null sebagai prasyarat.
Berbeda dengan skenario untuk menggunakan DisallowNull: Anda menggunakan atribut ini untuk menentukan bahwa argumen dari jenis referensi yang dapat diubah ke null tidak boleh null. Pertimbangkan properti di mana null adalah nilai default, tetapi klien hanya dapat mengaturnya ke nilai non-null. Pertimbangkan gambar berikut:
public string ReviewComment
{
get => _comment;
set => _comment = value ?? throw new ArgumentNullException(nameof(value), "Cannot set to null");
}
string _comment;
Kode sebelumnya adalah cara terbaik untuk mengekspresikan desain Anda bahwa ReviewComment bisa null tetapi tidak dapat diatur ke null. Setelah kode ini sadar null, Anda dapat mengekspresikan konsep ini dengan lebih jelas kepada pemanggil menggunakan System.Diagnostics.CodeAnalysis.DisallowNullAttribute:
[DisallowNull]
public string? ReviewComment
{
get => _comment;
set => _comment = value ?? throw new ArgumentNullException(nameof(value), "Cannot set to null");
}
string? _comment;
Dalam konteks nullable, ReviewCommentget aksesor dapat mengembalikan nilai default .null Compiler memperingatkan bahwa compiler harus diperiksa sebelum akses. Selain itu, ini memperingatkan pemanggil bahwa, meskipun bisa jadi null, pemanggil tidak boleh secara eksplisit mengaturnya ke null. Atribut DisallowNull ini juga menentukan pra-kondisi, tidak memengaruhi pengakses get. Anda menggunakan atribut DisallowNull saat mengamati karakteristik ini tentang:
- Variabel dapat
nulldalam skenario inti, sering kali saat pertama kali dibuat. - Variabel tidak boleh diatur secara eksplisit ke
null.
Situasi ini umum dalam kode yang awalnya tidak sadar null. Mungkin properti objek diatur dalam dua operasi inisialisasi yang berbeda. Mungkin beberapa properti diatur hanya setelah beberapa pekerjaan asinkron selesai.
Atribut AllowNull dan DisallowNull memungkinkan Anda menentukan bahwa prasyarat pada variabel mungkin tidak cocok dengan anotasi nullable pada variabel tersebut. Anotasi ini memberikan detail lebih lanjut tentang karakteristik API Anda. Informasi tambahan ini membantu pemanggil menggunakan API Anda dengan benar. Ingat bahwa Anda menentukan prasyarat menggunakan atribut berikut:
- AllowNull: Argumen yang tidak dapat diubah ke null mungkin null.
- DisallowNull: Argumen nullable tidak boleh null.
Pascakondisi: MaybeNull dan NotNull
Misalkan Anda memiliki metode dengan tanda tangan berikut:
public Customer FindCustomer(string lastName, string firstName)
Anda mungkin menulis metode seperti ini untuk mengembalikan null ketika nama yang dicari tidak ditemukan.
null jelas menunjukkan bahwa rekaman tidak ditemukan. Dalam contoh ini, Anda mungkin akan mengubah jenis pengembalian dari Customer ke Customer?. Mendeklarasikan nilai yang dikembalikan sebagai jenis referensi yang dapat diubah ke null menentukan niat API ini dengan jelas:
public Customer? FindCustomer(string lastName, string firstName)
Untuk alasan yang tercakup dalam generik nullability teknik tersebut mungkin tidak menghasilkan analisis statis yang cocok dengan API Anda. Anda mungkin memiliki metode generik yang mengikuti pola serupa:
public T Find<T>(IEnumerable<T> sequence, Func<T, bool> predicate)
Metode mengembalikan null saat item yang dicari tidak ditemukan. Anda dapat mengklarifikasi bahwa metode mengembalikan null saat item tidak ditemukan dengan menambah anotasi MaybeNull ke pengembalian metode:
[return: MaybeNull]
public T Find<T>(IEnumerable<T> sequence, Func<T, bool> predicate)
Kode sebelumnya menginformasikan kepada penelepon bahwa nilai yang dikembalikan sebenarnya dapat null. Ini juga menginformasikan pengkompilasi bahwa metode dapat mengembalikan null ekspresi meskipun jenisnya tidak dapat diubah ke null. Saat Anda memiliki metode generik yang mengembalikan instans parameter jenisnya, T, Anda dapat mengekspresikan bahwa itu tidak pernah mengembalikan null menggunakan atribut NotNull.
Anda juga dapat menentukan bahwa nilai yang dikembalikan atau argumen tidak null meskipun jenisnya adalah jenis referensi yang dapat diubah ke null. Metode berikut adalah metode pembantu yang melemparkan jika argumen pertamanya adalah null:
public static void ThrowWhenNull(object value, string valueExpression = "")
{
if (value is null) throw new ArgumentNullException(nameof(value), valueExpression);
}
Anda dapat memanggil rutinitas ini sebagai berikut:
public static void LogMessage(string? message)
{
ThrowWhenNull(message, $"{nameof(message)} must not be null");
Console.WriteLine(message.Length);
}
Setelah mengaktifkan jenis referensi null, Anda ingin memastikan bahwa kode sebelumnya dikompilasi tanpa peringatan. Saat metode kembali, parameter value dijamin tidak null. Namun, dapat diterima untuk memanggil ThrowWhenNull dengan referensi null. Anda dapat membuat value jenis referensi yang dapat diubah ke null, dan menambahkan pasca-kondisi NotNull ke deklarasi parameter:
public static void ThrowWhenNull([NotNull] object? value, string valueExpression = "")
{
_ = value ?? throw new ArgumentNullException(nameof(value), valueExpression);
// other logic elided
Kode sebelumnya mengekspresikan kontrak yang ada dengan jelas: Pemanggil dapat meneruskan variabel dengan nilai null, tetapi argumen dijamin tidak akan pernah null jika metode kembali tanpa melemparkan pengecualian.
Anda menentukan pascakondisi tanpa syarat menggunakan atribut berikut:
- MungkinNull: Nilai pengembalian yang tidak dapat diubah ke null dapat null.
- NotNull: Nilai pengembalian nullable tidak pernah null.
Kondisi pasca kondisi: NotNullWhen, MaybeNullWhen, dan NotNullIfNotNull
Anda mungkin terbiasa dengan string metode String.IsNullOrEmpty(String). Metode ini mengembalikan true saat argumen null atau string kosong. Ini adalah bentuk pemeriksaan null: Pemanggil tidak perlu memeriksa null argumen jika metode mengembalikan false. Untuk membuat metode seperti sadar null ini, Anda akan mengatur argumen ke jenis referensi yang dapat diubah ke null, dan menambahkan NotNullWhen atribut :
bool IsNullOrEmpty([NotNullWhen(false)] string? value)
Itu menginformasikan compiler bahwa kode apa pun di mana nilai false yang dikembalikan tidak memerlukan pemeriksaan null. Penambahan atribut menginformasikan analisis statis compiler bahwa IsNullOrEmpty melakukan pemeriksaan null yang dibutuhkan: saat mengembalikan false, argumen bukan null.
string? userInput = GetUserInput();
if (!string.IsNullOrEmpty(userInput))
{
int messageLength = userInput.Length; // no null check needed.
}
// null check needed on userInput here.
Metode String.IsNullOrEmpty(String) ini seperti yang ditunjukkan pada contoh sebelumnya. Anda mungkin memiliki metode serupa di basis kode Anda yang memeriksa status objek untuk nilai null. Pengompilasi tidak mengenali metode pemeriksaan null kustom, dan Anda perlu menambahkan anotasi sendiri. Saat Anda menambahkan atribut, analisis statis kompilator tahu kapan variabel yang diuji diperiksa null.
Penggunaan lain untuk atribut ini adalah pola Try*. Pascakondisi untuk argumen ref dan out dikomunikasikan melalui nilai yang dikembalikan. Pertimbangkan metode ini yang ditunjukkan sebelumnya (dalam konteks nonaktif null):
bool TryGetMessage(string key, out string message)
{
if (_messageMap.ContainsKey(key))
message = _messageMap[key];
else
message = null;
return message != null;
}
Metode sebelumnya mengikuti idiom .NET yang khas: nilai pengembalian menunjukkan apakah message diatur ke nilai yang dicari atau, jika tidak ada pesan yang ditemukan, ke nilai default. Jika metode mengembalikan true, nilai message tidak null; jika tidak, metode mengatur message ke null.
Dalam konteks yang diaktifkan nullable, Anda dapat mengomunikasikan idiom tersebut NotNullWhen menggunakan atribut . Saat Anda membuat anotasi parameter untuk jenis referensi yang dapat diubah ke null, buat message menjadi string? dan tambahkan atribut:
bool TryGetMessage(string key, [NotNullWhen(true)] out string? message)
{
if (_messageMap.ContainsKey(key))
message = _messageMap[key];
else
message = null;
return message is not null;
}
Dalam contoh sebelumnya, nilai message diketahui tidak null saat TryGetMessage mengembalikan true. Anda harus membuat anotasi metode serupa dalam basis kode Anda dengan cara yang sama: argumen bisa sama dengan null, dan diketahui tidak null saat metode mengembalikan true.
Ada satu atribut akhir yang mungkin juga Anda butuhkan. Terkadang status null dari nilai yang dikembalikan tergantung pada status null dari satu atau beberapa argumen. Metode ini mengembalikan nilai non-null setiap kali argumen tertentu bukan null. Untuk membuat anotasi metode ini dengan benar, Anda menggunakan atribut NotNullIfNotNull. Pertimbangkan kode berikut:
string GetTopLevelDomainFromFullUrl(string url)
Jika argumen url tidak null, outputnya bukan null. Setelah referensi nullable diaktifkan, Anda perlu menambahkan lebih banyak anotasi jika API Anda dapat menerima argumen null. Anda dapat membuat anotasi jenis pengembalian seperti yang ditunjukkan dalam kode berikut:
string? GetTopLevelDomainFromFullUrl(string? url)
Itu juga berfungsi, tetapi sering memaksa penelepon untuk menerapkan pemeriksaan tambahan null . Kontraknya adalah bahwa nilai pengembalian hanya akan null saat argumen url adalah null. Untuk mengekspresikan kontrak tersebut, Anda akan membuat anotasi metode ini seperti yang ditunjukkan dalam kode berikut:
[return: NotNullIfNotNull(nameof(url))]
string? GetTopLevelDomainFromFullUrl(string? url)
Contoh sebelumnya menggunakan operator nameof untuk parameter url. Nilai yang dikembalikan dan argumen telah diannotasikan dengan ? menunjukkan bahwa salah satunya bisa berupa null. Atribut selanjutnya mengklarifikasi bahwa nilai pengembalian tidak null ketika url argumen bukan null.
Anda menentukan pascakondisi bersyarat menggunakan atribut ini:
-
MungkinNullWhen: Argumen yang tidak dapat diubah ke null dapat null ketika metode mengembalikan nilai yang ditentukan
bool. -
NotNullWhen: Argumen nullable tidak null ketika metode mengembalikan nilai yang ditentukan
bool. - NotNullIfNotNull: Nilai pengembalian bukan null jika argumen untuk parameter yang ditentukan bukan null.
Metode pembantu: MemberNotNull dan MemberNotNullWhen
Atribut ini menentukan niat Anda saat Anda merefaktor kode umum dari konstruktor ke dalam metode pembantu. Pengkompilasi C# menganalisis konstruktor dan penginisialisasi bidang untuk memastikan bahwa semua bidang referensi yang tidak dapat diubah ke null diinisialisasi sebelum setiap konstruktor kembali. Namun, compiler C# tidak melacak penetapan bidang melalui semua metode pembantu. Pomengompilasi mengeluarkan peringatan CS8618 saat bidang tidak diinisialisasi langsung di konstruktor, melainkan dalam metode pembantu. Anda menambah MemberNotNullAttribute ke deklarasi metode dan menentukan bidang yang diinisialisasi ke nilai non-null dalam metode. Misalnya, pertimbangkan contoh berikut:
public class Container
{
private string _uniqueIdentifier; // must be initialized.
private string? _optionalMessage;
public Container()
{
Helper();
}
public Container(string message)
{
Helper();
_optionalMessage = message;
}
[MemberNotNull(nameof(_uniqueIdentifier))]
private void Helper()
{
_uniqueIdentifier = DateTime.Now.Ticks.ToString();
}
}
Anda dapat menentukan beberapa nama bidang sebagai argumen ke konstruktor atribut MemberNotNull.
MemberNotNullWhenAttribute memiliki argumen bool. Anda menggunakan MemberNotNullWhen dalam situasi di mana metode pembantu Anda mengembalikan bool yang menunjukkan apakah metode pembantu Anda menginisialisasi bidang.
Hentikan analisis nullable saat metode yang dipanggil melempar
Beberapa metode, biasanya pembantu pengecualian, atau metode utilitas lainnya, selalu keluar dengan melemparkan pengecualian. Atau, pembantu melempar pengecualian berdasarkan nilai argumen Boolean.
Dalam kasus pertama, Anda dapat menambahkan atribut DoesNotReturnAttribute ke deklarasi metode. Analisis status null compiler tidak memeriksa kode apa pun dalam metode yang mengikuti panggilan ke metode yang diannotasikan dengan DoesNotReturn. Pertimbangkan metode ini:
[DoesNotReturn]
private void FailFast()
{
throw new InvalidOperationException();
}
public void SetState(object containedField)
{
if (containedField is null)
{
FailFast();
}
// containedField can't be null:
_field = containedField;
}
Compiler tidak mengeluarkan peringatan apa pun setelah panggilan ke FailFast.
Dalam kasus kedua, Anda menambah atribut System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute ke parameter Boolean dari metode. Anda dapat mengubah contoh sebelumnya sebagai berikut:
private void FailFastIf([DoesNotReturnIf(true)] bool isNull)
{
if (isNull)
{
throw new InvalidOperationException();
}
}
public void SetFieldState(object? containedField)
{
FailFastIf(containedField == null);
// No warning: containedField can't be null here:
_field = containedField;
}
Saat nilai argumen cocok dengan nilai konstruktor, compiler tidak melakukan analisis DoesNotReturnIfstatus null setelah metode tersebut.
Ringkasan
Menambahkan jenis referensi nullable menyediakan kosakata awal untuk menjelaskan ekspektasi API Anda untuk variabel yang bisa berupa null. Atribut menyediakan kosakata yang lebih kaya untuk menggambarkan status variabel null sebagai prasyarat dan pascakondisi. Atribut ini lebih jelas menggambarkan harapan Anda dan memberikan pengalaman yang lebih baik bagi pengembang menggunakan API Anda.
Saat Anda memperbarui pustaka untuk konteks yang dapat diubah ke null, tambahkan atribut ini untuk memandu pengguna API Anda ke penggunaan yang benar. Atribut ini membantu Anda sepenuhnya menjelaskan status null argumen dan mengembalikan nilai.
- AllowNull: Bidang, parameter, atau properti yang tidak dapat diubah ke null mungkin null.
- DisallowNull: Bidang, parameter, atau properti yang dapat diubah ke null tidak boleh null.
- MungkinNull: Nilai bidang, parameter, properti, atau pengembalian yang tidak dapat diubah ke null mungkin null.
- NotNull: Bidang, parameter, properti, atau nilai yang dikembalikan null tidak pernah null.
-
MungkinNullWhen: Argumen yang tidak dapat diubah ke null mungkin null ketika metode mengembalikan nilai yang ditentukan
bool. -
NotNullWhen: Argumen nullable tidak null ketika metode mengembalikan nilai yang ditentukan
bool. - NotNullIfNotNull: Parameter, bidang, properti, atau nilai pengembalian bukan null jika argumen untuk parameter yang ditentukan bukan null.
- DoesNotReturn: Metode atau properti tidak pernah kembali. Dengan kata lain, itu selalu melemparkan pengecualian.
-
DoesNotReturnIf: Metode atau properti ini tidak pernah kembali jika parameter
boolmemiliki nilai yang ditentukan.