Null Birleştirme Operatörü ile Null Nesneleri Örnekleme


12

Aşağıdaki tipik senaryoyu düşünün:

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

Sıfır birleştirici operatörü kullanarak aşağıdaki değiştirme hakkında ne düşündüğünü merak ediyorum:

myObject = myObject ?? new myClass();

İkinci formu kullanıp kullanmamam gerektiğinden emin değilim. Güzel bir steno gibi görünüyor, ama myObject = myObjectbaşlangıçtaki yapı biraz kod kokusu gibi görünebilir.

Bu yapılacak makul bir şey mi, yoksa kaçırdığım daha iyi bir stenografi var mı? Veya belki, "Bu üç satır, üstesinden gel!"?

Düzenleme: Bahsedildiği gibi, belki de bu tipik bir senaryo demek abartı bir şeydir. Genellikle henüz doldurulmuş olabilir veya olmayabilir çocuk başvuru türü özelliği olan bir veritabanından bir varlık alırken bu durumla karşılaşıyorum:

myClass myObject = myClassService.getById(id);
myObject.myChildObject = myObject.myChildObject ?? new myChildClass();

15
Yeni başlayanlar bunun gibi şeylerin "hackish" olduğuna inanıyor, daha deneyimli geliştiriciler sadece "deyimsel" diyorlar.
Doc Brown

Nesne bir değer nesnesine benziyorsa (deyimsel konuşmada "değer anlambilimine sahiptir"), türünün bir değerinin MyClassbir public static readonlyüyesini sağlamalıdır Empty. String.EmptyMSDN'ye bakın .
rwong


5
Bir yok mudur ??=santral?
aviv

1
@aviv keşke olsaydı!
Loren Pechtel

Yanıtlar:


16

Her zaman boş birleştirme operatörü kullanıyorum. Özlü olmasını seviyorum.

Bu operatörün doğada üçlü operatöre (A? B: C) benzer olduğunu düşünüyorum. Okuması ikinci doğadan önce biraz pratik gerektirir, ancak alıştıktan sonra okunabilirliğin uzun el versiyonları üzerinde geliştiğini hissediyorum.

Ayrıca, açıkladığınız durum operatörün yararlı olduğu tek bir senaryodur. Bunun gibi yapıları değiştirmek de yararlıdır:

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

veya

return value != null ? value : otherValue;

ile

return value ?? otherValue;

Bu operatörün kullanımı konusunda genel olarak kesinlikle katılıyorum. Bununla birlikte, onu kullanmaya ilişkin referanslar gördüğümde, bu genellikle böyle bir şeydir myObject = myObject2 ?? myObject3. Özellikle merak ettiğim şey, null olmadığı sürece kendisine bir nesne ayarlamak için operatörü kullanmaktır.
grin0048

2
Her iki durumda da aynı mantık geçerlidir. Aynı mantığı ifade etmenin daha özlü bir yolu.
17 of 26

Bu üç formun her biri için IL'ye baktığımı hatırlıyorum. Birincisi ve ikincisi özdeşti, ancak üçüncüsü nullbir karşılaştırma olduğunu varsayabileceği gibi bir şekilde optimize edildi.
Jesse C. Slicer

2

Özellikle merak ettiğim şey, null olmadığı sürece kendisine bir nesne ayarlamak için operatörü kullanmaktır.

?? operatorBoş-birleştirici operatör olarak adlandırılır ve null değer türleri veya referans türleri için varsayılan bir değer tanımlamak için kullanılır. İşlenen boş değilse, soldaki işleneni döndürür; aksi takdirde doğru işleneni döndürür.

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

Boş birleştirici işleç hakkında daha fazla ayrıntı ve kod örneği - MSDN makalesi .

more than nullableDurumu kontrol ederseniz , alternatif olarak Üçlü operatörünü kullanabilirsiniz.

Üçlü operatör

Şuna da bakabilirsiniz : Operatör . Üçlü veya koşullu operatör olarak adlandırılır . Koşullu işleç (? :), bir Boole ifadesinin değerine bağlı olarak iki değerden birini döndürür.

Null olabilecek bir tür bir değer içerebilir veya tanımsız olabilir. ?? operatör, boş olmayan bir tipe boş değerli bir tür atandığında döndürülecek varsayılan değeri tanımlar. Null değeri olmayan bir değer türüne null değeri olmayan bir değer atamaya çalışırsanız, ?? bir derleme zamanı hatası üreteceksiniz. Bir döküm kullanırsanız ve nullable değer türü şu anda tanımsızsa, bir InvalidOperationException istisnası atılır.

MSDN -? ' Dan bir kod örneği : Operator (C # Reference) :

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

// ?: conditional operator.
classify = (input.HasValue) ? ((input < 0) ? "negative" : "positive") : "undefined";

Sorudan örnek almak ve koşullu operatörü uygulamak gibi bir şeyimiz olurdu myObject = (myObject == null) ? new myClass() : myObject. Bu nedenle, koşullu operatörün daha iyi bir kullanımını kullanmazsam, null birleştirme operatörü olarak bir nesnenin kendisine (boş değilse) ayarlanmasıyla aynı "soruna" sahip gibi görünüyor ve daha az özlü.
grin0048

Birden fazla koşulu kontrol ediyorsanız (null değil ve sıfırdan büyük) - koşullu operatör bunu yapacaktır. Ancak, sadece null kontrol işe yarayacak ?? Şebeke.
Yusubov

2

Senaryo tipik (ya da en azından olmalı) sanmıyorum.

Bazı alanların varsayılan değerinin olmamasını istiyorsanız null, alan başlatıcıda ayarlayın:

myClass myObject = new myClass();

Veya başlatma daha karmaşıksa, yapıcıda ayarlayın.

Oluşturmak istediğiniz takdirde myClasssadece gerçekten (oluşturduktan uzun zaman alır, çünkü örneğin) o, o zaman kullanabilirsiniz gerektiğinde Lazy<T>:

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

(Bu varsayılan kurucu çağırır. Başlatma daha komplike ise, yaratan lambda geçmesi myClassiçin Lazy<T>yapıcısı.)

Değere erişmek için myObject.Value, ilk kez erişiyorsanız başlatma işlemini çağıracak olan tuşunu kullanın myObject.Value.


IMO tembel oluşturma yalnızca sonuçta ortaya çıkan nesneye ihtiyacınız olduğu garanti edilmezse yararlıdır, tembel yaratılış kullandığım tek şey, bir şey değiştiğinde sıfırladığım nakit paradan türetilmiş bir sonuca sahip olduğum ve aynı sonuca çok ihtiyacım olacağını biliyorum ve recalc pahalıdır. diğer bilge Ben sadece null kontrol ile uğraşmak istemiyorum
cırcır ucube

@ratchetfreak Evet, bu yüzden önce alan başlatıcısı önerdim.
svick

Başka durumlar da var. Şu anda baktığım şey: İlk geçiş istisna durumlarını belirler. İkinci geçiş, diğer her şey için varsayılanları belirler. ?? = çizgiyi yarıya indirir.
Loren Pechtel

1

Özellikle ??isteğe bağlı yöntem parametreleriyle birlikte kullanmayı seviyorum . Aşırı yüklenme ihtiyacını sınırlandırıyorum ve şeyin bir değere sahip olmasını sağlıyorum.

public void DoSomething (MyClass thing1 = null) {
    thing1 = thing1 ?? new MyClass();
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.