Jenis referensi yang dapat diubah ke null (referensi C#)

Catatan

Artikel ini mencakup jenis referensi yang dapat diubah ke null. Anda juga dapat mendeklarasikan jenis nilai yang dapat diubah ke null.

Jenis referensi nullable tersedia dalam kode yang telah memilih konteks sadar null. Jenis referensi yang dapat diubah ke null, peringatan analisis statik null, dan operator null-forgiving adalah fitur bahasa opsional. Semua dinonaktifkan secara default. Konteks yang dapat diubah ke null dikontrol di tingkat proyek menggunakan pengaturan build, atau dalam kode menggunakan pragma.

Penting

Semua template proyek yang dimulai dengan .NET 6 (C# 10) mengaktifkan konteks yang dapat diubah ke null untuk proyek tersebut. Proyek yang dibuat dengan template sebelumnya tidak menyertakan elemen ini, dan fitur ini tidak aktif kecuali Anda mengaktifkannya di file proyek atau menggunakan pragma.

Dalam konteks sadar yang dapat diubah ke null:

  • Variabel dengan jenis referensi T harus diinisialisasi dengan bukan null, dan tidak boleh diberi nilai yang mungkin null.
  • Variabel dari jenis referensi T? dapat diinisialisasi dengan null atau ditetapkan null, tetapi harus diperiksa terhadap null sebelum de-referencing.
  • Variabel m dari jenis T? dianggap bukan null saat Anda menerapkan operator null-forgiving, seperti pada m!.

Perbedaan antara jenis referensi yang tidak dapat diubah ke null T dan jenis referensi yang dapat diubah ke null T? diberlakukan oleh interpretasi kompilator dari aturan sebelumnya. Variabel jenis T dan variabel jenis T? diwakili oleh jenis .NET yang sama. Contoh berikut mendeklarasikan string yang tidak dapat diubah ke null dan string yang dapat diubah ke null, lalu menggunakan operator null-forgiving untuk menetapkan nilai ke string yang tidak dapat diubah ke null:

string notNull = "Hello";
string? nullable = default;
notNull = nullable!; // null forgiveness

Variabel notNull dan nullable keduanya diwakili oleh jenis String. Karena jenis yang tidak dapat diubah ke null dan dapat diubah ke null keduanya disimpan sebagai jenis yang sama, ada beberapa lokasi yang penggunaan jenis referensi yang dapat diubah ke null-nya tidak diperbolehkan. Secara umum, jenis referensi yang dapat diubah ke null tidak dapat digunakan sebagai kelas dasar atau antarmuka yang diterapkan. Jenis referensi yang dapat diubah ke null tidak dapat digunakan dalam pembuatan objek atau ekspresi pengujian jenis apa pun. Jenis referensi yang dapat diubah ke null tidak bisa menjadi jenis ekspresi akses anggota. Contoh berikut menunjukkan konstruksi ini:

public MyClass : System.Object? // not allowed
{
}

var nullEmpty = System.String?.Empty; // Not allowed
var maybeObject = new object?(); // Not allowed
try
{
    if (thing is string? nullableString) // not allowed
        Console.WriteLine(nullableString);
} catch (Exception? e) // Not Allowed
{
    Console.WriteLine("error");
}

Referensi yang dapat diubah ke null dan analisis statik

Contoh di bagian sebelumnya mengilustrasikan sifat jenis referensi yang dapat diubah ke null. Jenis referensi yang dapat diubah ke null bukanlah jenis kelas baru, melainkan anotasi pada jenis referensi yang ada. Kompilator menggunakan anotasi tersebut untuk membantu Anda menemukan potensi kesalahan referensi null dalam kode Anda. Tidak ada perbedaan runtime antara jenis referensi yang tidak dapat diubah ke null dan jenis referensi yang dapat diubah ke null. Kompilator tidak menambahkan pemeriksaan runtime untuk jenis referensi yang tidak dapat diubah ke null. Keuntungannya ada pada analisis waktu kompilasi. Kompilator menghasilkan peringatan yang membantu Anda menemukan dan memperbaiki potensi kesalahan null dalam kode Anda. Anda mendeklarasikan niat Anda, dan kompilator memperingatkan Anda ketika kode Anda melanggar niat tersebut.

Dalam konteks yang diaktifkan yang dapat diubah ke null, kompilator melakukan analisis statik pada variabel dari semua jenis referensi, baik yang dapat diubah ke null dan yang tidak dapat diubah ke null. Kompilator melacak status null dari setiap variabel referensi sebagai bukan null atau mungkin null. Status default referensi yang tidak dapat diubah ke null adalah bukan null. Status default referensi yang dapat diubah ke null adalah mungkin null.

Jenis referensi yang tidak dapat diubah ke null harus selalu aman untuk direferensikan karena status null-nya adalah bukan null. Untuk memberlakukan aturan tersebut, kompilator mengeluarkan peringatan jika jenis referensi yang tidak dapat diubah ke null tidak diinisialisasi ke nilai yang bukan null. Variabel lokal harus ditetapkan di tempatnya dideklarasikan. Setiap bidang harus diberi nilai bukan null, dalam penginisialisasi bidang atau setiap konstruktor. Kompilator mengeluarkan peringatan saat referensi yang tidak dapat diubah ke null ditetapkan ke referensi yang statusnya mungkin null. Umumnya, referensi yang tidak dapat diubah ke null adalah bukan null dan tidak ada peringatan yang dikeluarkan saat variabel tersebut didereferensikan.

Catatan

Jika Anda menetapkan ekspresi mungkin-null ke jenis referensi yang tidak dapat diubah ke null, pengkompilasi akan menghasilkan peringatan. Kompilator kemudian membuat peringatan untuk variabel tersebut hingga variabel tersebut ditetapkan ke ekspresi bukan null.

Jenis referensi yang dapat diubah ke null dapat diinisialisasi atau ditetapkan ke null. Oleh karena itu, analisis statik harus menentukan bahwa suatu variabel bukan null sebelum direferensikan. Jika referensi yang dapat diubah ke null ditentukan sebagai mungkin null, menetapkan ke variabel referensi yang tidak dapat diubah ke null menghasilkan peringatan kompilator. Kelas berikut menunjukkan contoh peringatan ini:

public class ProductDescription
{
    private string shortDescription;
    private string? detailedDescription;

    public ProductDescription() // Warning! shortDescription not initialized.
    {
    }

    public ProductDescription(string productDescription) =>
        this.shortDescription = productDescription;

    public void SetDescriptions(string productDescription, string? details=null)
    {
        shortDescription = productDescription;
        detailedDescription = details;
    }

    public string GetDescription()
    {
        if (detailedDescription.Length == 0) // Warning! dereference possible null
        {
            return shortDescription;
        }
        else
        {
            return $"{shortDescription}\n{detailedDescription}";
        }
    }

    public string FullDescription()
    {
        if (detailedDescription == null)
        {
            return shortDescription;
        }
        else if (detailedDescription.Length > 0) // OK, detailedDescription can't be null.
        {
            return $"{shortDescription}\n{detailedDescription}";
        }
        return shortDescription;
    }
}

Cuplikan berikut menunjukkan di mana compiler mengeluarkan peringatan saat menggunakan kelas ini:

string shortDescription = default; // Warning! non-nullable set to null;
var product = new ProductDescription(shortDescription); // Warning! static analysis knows shortDescription maybe null.

string description = "widget";
var item = new ProductDescription(description);

item.SetDescriptions(description, "These widgets will do everything.");

Contoh sebelumnya menunjukkan bagaimana analisis statik kompilator menentukan status null dari variabel referensi. Kompilator menerapkan aturan bahasa untuk pemeriksaan dan penugasan null untuk menginformasikan analisisnya. Kompilator tidak dapat membuat asumsi tentang semantik metode atau properti. Jika Anda memanggil metode yang melakukan pemeriksaan null, kompilator tidak dapat mengetahui bahwa metode tersebut memengaruhi status null variabel. Ada atribut yang dapat Anda tambahkan ke API untuk memberi tahu kompilator tentang semantik argumen dan nilai kembali. Atribut ini telah diterapkan ke banyak API umum di pustaka .NET Core. Misalnya, IsNullOrEmpty telah diperbarui, dan kompilator menafsirkan metode tersebut dengan benar sebagai pemeriksaan null. Untuk informasi selengkapnya tentang atribut yang berlaku untuk analisis statik status null, lihat artikel tentang Atribut yang dapat diubah ke null.

Mengatur konteks yang dapat diubah ke null

Ada dua cara untuk mengontrol konteks yang dapat diubah ke null. Di tingkat proyek, Anda dapat menambahkan pengaturan proyek <Nullable>enable</Nullable>. Dalam satu file sumber C#, Anda dapat menambahkan pragma #nullable enable untuk mengaktifkan konteks yang dapat diubah ke null. Lihat artikel tentang menetapkan strategi yang dapat diubah ke null. Sebelum .NET 6, proyek baru menggunakan default, <Nullable>disable</Nullable>. Dimulai dengan .NET 6, proyek baru menyertakan elemen <Nullable>enable</Nullable> dalam file proyek.

Spesifikasi bahasa C#

Untuk informasi selengkapnya, lihat proposal berikut untuk spesifikasi bahasa C#:

Lihat juga