Instantiating Objek Null dengan Operator Null-Penggabungan

12

Pertimbangkan skenario khas berikut:

if(myObject == null) {
    myObject = new myClass();
}

Saya ingin tahu apa yang dipikirkan tentang penggantian berikut ini menggunakan operator null-coalescing:

myObject = myObject ?? new myClass();

Saya tidak yakin apakah saya harus menggunakan formulir kedua. Sepertinya steno yang bagus, tetapi myObject = myObjectkonstruk di awal sepertinya seperti sedikit bau kode.

Apakah ini hal yang masuk akal untuk dilakukan, atau adakah steno yang lebih baik yang saya lewatkan? Atau mungkin, "Ini tiga baris, lupakan saja!"?

Sunting: Seperti telah disebutkan, mungkin menyebut ini skenario khas adalah sesuatu yang berlebihan. Saya biasanya menemukan bahwa saya menghadapi situasi ini ketika saya mengambil entitas dari database yang memiliki properti tipe referensi anak yang mungkin belum atau belum diisi:

myClass myObject = myClassService.getById(id);
myObject.myChildObject = myObject.myChildObject ?? new myChildClass();
Grin0048
sumber
15
Pemula percaya hal-hal seperti ini sebagai "retas", para pengembang yang lebih berpengalaman menyebutnya "idiomatik".
Doc Brown
Jika objek terlihat seperti objek nilai ("memiliki semantik nilai", dalam bahasa idiomatik), MyClassharus memberikan public static readonlyanggota Emptynilai dari jenisnya. Lihat String.Emptydi MSDN .
rwong
5
Apakah tidak ada ??=operator?
aviv
1
@aviv Saya berharap ada!
Loren Pechtel

Jawaban:

16

Saya menggunakan operator penggabungan nol sepanjang waktu. Saya suka keringkasannya.

Saya menemukan operator ini memiliki sifat yang mirip dengan operator ternary (A? B: C). Dibutuhkan sedikit latihan sebelum membaca itu adalah sifat kedua, tetapi begitu Anda terbiasa, saya merasa keterbacaan meningkat dari versi lama.

Juga, situasi yang Anda gambarkan hanyalah satu skenario di mana operator berguna. Juga berguna untuk mengganti konstruksi seperti ini:

if (value != null)
{
    return value;
}
else
{ 
    return otherValue;
}

atau

return value != null ? value : otherValue;

dengan

return value ?? otherValue;
17 dari 26
sumber
Setuju secara umum tentang penggunaan operator ini. Namun, ketika saya melihat referensi untuk menggunakannya, biasanya seperti ini myObject = myObject2 ?? myObject3. Yang saya ingin tahu secara spesifik adalah menggunakan operator untuk mengatur objek ke dirinya sendiri kecuali itu nol.
grin0048
2
Saya pikir alasan yang sama berlaku dalam kedua kasus itu. Ini cara yang lebih ringkas untuk mengekspresikan logika yang sama.
17 dari 26
Saya ingat melihat IL untuk masing-masing dari tiga bentuk sekaligus. Yang pertama dan yang kedua identik, tetapi yang ketiga dioptimalkan dengan cara yang bisa diasumsikan nullsebagai perbandingan.
Jesse C. Slicer
2

Yang saya ingin tahu secara spesifik adalah menggunakan operator untuk mengatur objek ke dirinya sendiri kecuali itu nol.

Ini ?? operatordisebut operator penggabungan nol dan digunakan untuk menentukan nilai default untuk tipe nilai yang dapat dibatalkan atau tipe referensi. Ini mengembalikan operan kiri jika operan tidak nol; jika tidak mengembalikan operan yang tepat.

myObject = myObject ?? new myObject(); - instantiate default value of object

Lebih detail dan contoh kode tentang operator penggabungan nol - artikel MSDN .

Jika Anda memeriksa more than nullablekondisinya, sebagai alternatif Anda dapat menggunakan operator Ternary.

Operator ternary

Anda juga dapat melihat ?: Operator . Ini disebut operator ternary atau kondisional . Operator kondisional (? :) mengembalikan satu dari dua nilai tergantung pada nilai ekspresi Boolean.

Jenis yang dapat dibatalkan dapat berisi nilai, atau dapat ditentukan. Itu ?? operator menetapkan nilai default yang akan dikembalikan ketika tipe nullable ditugaskan ke tipe non-nullable. Jika Anda mencoba menetapkan tipe nilai nullable ke tipe nilai non-nullable tanpa menggunakan ?? operator, Anda akan menghasilkan kesalahan waktu kompilasi. Jika Anda menggunakan gips, dan tipe nilai nullable saat ini tidak terdefinisi, pengecualian InvalidOperationException akan dibuang.

Contoh kode dari MSDN -?: Operator (Referensi C #) :

int? input = Convert.ToInt32(Console.ReadLine());
string classify;

// ?: conditional operator.
classify = (input.HasValue) ? ((input < 0) ? "negative" : "positive") : "undefined";
Yusubov
sumber
Jadi mengambil contoh dari pertanyaan dan menerapkan operator bersyarat, kita akan memiliki sesuatu seperti myObject = (myObject == null) ? new myClass() : myObject. Jadi, kecuali saya kehilangan penggunaan yang lebih baik dari operator kondisional, tampaknya memiliki "masalah" yang sama dengan menetapkan objek ke dirinya sendiri (jika tidak nol) sebagai operator penggabungan null - dan kurang ringkas.
grin0048
Jika Anda memeriksa lebih dari satu syarat (Tidak nol dan lebih besar dari nol) - maka operator kondisional akan melakukannya. Namun, hanya memeriksa nol akan berhasil ?? operator.
Yusubov
2

Saya tidak berpikir bahwa skenario itu (atau paling tidak seharusnya) tipikal.

Jika Anda ingin nilai default beberapa bidang tidak menjadi null, maka setel di penginisialisasi bidang:

myClass myObject = new myClass();

Atau, jika inisialisasi lebih rumit, atur di konstruktor.

Jika Anda ingin membuat myClasshanya ketika Anda benar-benar membutuhkannya (mis. Karena membuatnya membutuhkan waktu lama), maka Anda dapat menggunakan Lazy<T>:

Lazy<myClass> myObject = new Lazy<myClass>();

(Ini memanggil konstruktor default. Jika inisialisasi lebih rumit, berikan lambda yang membuat myClasske Lazy<T>konstruktor.)

Untuk mengakses nilai, gunakan myObject.Value, yang akan memanggil inisialisasi jika ini adalah pertama kalinya Anda mengakses myObject.Value.

svick
sumber
IMO lazy creation hanya berguna jika Anda tidak dijamin membutuhkan objek yang dihasilkan, hanya saja saat saya menggunakan lazy creation adalah ketika saya memiliki hasil turunan yang dicairkan yang saya atur ulang ketika sesuatu berubah dan saya tahu bahwa saya akan membutuhkan hasil yang sama banyak dan recalc itu mahal. bijaksana lain saya hanya tidak ingin repot dengan cek nol
ratchet freak
@ scratchetfreak Ya, itulah sebabnya saya menyarankan inisialisasi bidang terlebih dahulu.
svick
Ada juga kasus lain. Apa yang saya lihat saat ini: Pass pertama menetapkan kasus pengecualian. Pass kedua menetapkan default untuk yang lainnya. ?? = akan memotong garis menjadi dua.
Loren Pechtel
1

Saya terutama suka menggunakan ??dalam hubungannya dengan parameter metode opsional. Saya membatasi kebutuhan untuk kelebihan dan memastikan benda itu memiliki nilai.

public void DoSomething (MyClass thing1 = null) {
    thing1 = thing1 ?? new MyClass();
}
radarbob
sumber