C # için özellik birleştirme operatörü


9

C # 'da null birleştirme operatörü kodu kısaltmanıza izin verir

  if (_mywidget == null)
     return new Widget();
  else
     return _mywidget;

Aşağı:

  return _mywidget ?? new Widget();

C # içinde olmasını istediğim yararlı bir işleç, bir nesnenin bir özelliğini veya nesne null ise başka bir değeri döndürmenize izin veren bir operatör olacağını bulmaya devam ediyorum. Bu yüzden değiştirmek istiyorum

  if (_mywidget == null)
     return 5;
  else
     return _mywidget.Length;

İle:

  return _mywidget.Length ??! 5;

Bu operatörün var olmaması için bir neden olması gerektiğini düşünmeye yardım edemem. Kod kokusu mu? Bunu yazmanın daha iyi bir yolu var mı? (Boş nesne deseninin farkındayım ancak bu dört kod satırını değiştirmek için kullanmak aşırıya kaçmış gibi görünüyor.)


1
Koşullu operatör burada yeterli olur mu?
Anon.

1
Birisi böyle bir şey yapmanıza izin veren bir şey yazdı: string location = worker.office.address.location ?? "Bilinmeyen"; . Bu wil seti konumu için "Bilinmeyen" nesnesi (ya birisi zaman çalışanın , ofis , adres veya konum ) boş. Ne yazık ki, kimin yazdığını ya da nerede gönderdiğini hatırlamıyorum. Tekrar bulursam, buraya göndereceğim!
Kristof Claes

1
Bu soru StackOverflow üzerinde çok daha fazla çekiş elde edecektir.
İş

2
??!C ++ 'da bir operatördür. :-)
James McNellis

Yanıtlar:


5

Ben güvenle her biri null olup olmadığını kontrol etmek zorunda kalmadan x.Prop.SomeOtherProp.ThirdProp yapmak sağlayan bir C # dil özelliği istiyorum. Bir sürü "derin özellik geçişleri" bu tür yapmak zorunda bir kod temasında, NullReferenceExceptions yuttu Navigate adlı bir uzantı yöntemi yazdı ve bunun yerine varsayılan bir değer döndürdü. Yani böyle bir şey yapabilirdim:

var propVal = myThing.Navigate(x => x.PropOne.PropTwo.PropThree.PropFour, defaultValue);

Bunun dezavantajı, farklı bir kod kokusuna sahip olmasıdır: yutulmuş istisnalar. Bu "doğru" gibi bir şey yapmak isterseniz, lamdba'yı bir ifade olarak alabilir ve her özellik erişimcisinin etrafına boş denetimler eklemek için ifadeyi anında değiştirebilirsiniz. "Hızlı ve kirli" için gittim ve bu "daha iyi" bir şekilde uygulamak vermedi. Ama belki bazı yedek düşünce döngülerim olduğunda bunu tekrar ziyaret edip bir yere gönderirim.

Sorunuzu daha doğrudan yanıtlamak için, bunun bir özellik olmamasının nedeni, özelliği uygulama maliyetinin, özelliğe sahip olmanın avantajını aşmasıdır. C # ekibi hangi özelliklere odaklanacağını seçmeli ve seçmeli ve bu henüz zirveye çıkmadı. Herhangi bir içeriden bilgi yok rağmen sadece bir tahmin.


1
Tam olarak düşündüğüm, ancak güvenli yolun performansı oldukça kötü olurdu sanırım (birçok Expression.Compile () nedeniyle) ... C # 'da uygulanmadığı çok kötü (Obj.?PropA.?Prop1 gibi bir şey)
Guillaume86

x.PropOne.PropTwo.PropThree.PropFour Demeter Yasasını ihlal ettiği için kötü bir tasarım seçeneğidir. Yöntemlerinizi / sınıflarınızı, bunu kullanmanıza gerek kalmayacak şekilde yeniden tasarlayın.
Justin Shield

Demeter Yasası ışığında derin mülkiyet erişiminden kaçınmak, bir veritabanını dikkatsizce normalleştirmek kadar tehlikelidir. Çok ileri gidebilirsin.
Mir

3
C # 6.0'da bu, Null-Koşullu İşleci (Elvis operatörü olarak da bilinir) kullanarak mümkündür msdn.microsoft.com/en-us/magazine/dn802602.aspx
victorvartan

15

Şimdi C # 6 ile bunu yapabileceğinize inanıyorum:

return _mywidget?.Length ?? 5;

?.Sol taraftaki null koşullu operatöre dikkat edin. _mywidget?.Lengthnull olursa null değerini döndürür _mywidget.

Diğerlerinin önerdiği gibi, basit bir üçlü operatörü okumak daha kolay olabilir.


9

Neden yapmadıklarına dair sadece spekülasyon. Sonuçta, inanmıyorum ?? ilk C # sürümündeydi.

Her neyse, sadece koşullu operatörü kullanacak ve bir gün diyeceğim:

return (_mywidget != null) ? _mywidget.Length : 5;

?? koşullu işleç için yalnızca bir kısayoldur.


5
Kişisel olarak, bu ilk etapta bunu yapmak için bir operatöre sahip olmak kadar kötü (imho). Bir nesneden bir şey istersiniz ... bu nesne orada olmayabilir ... o zaman orada olmaması durumunda 5cevap olarak verelim . Özel operatörler istemeye başlamadan önce tasarımınıza bakmanız gerekir.
Moo-Juice

1
@ Moo-Juice Bu kodu koruyan kişiyi hayal ediyorum, 'Bu bana neden 5 veriyor? Hrmmm. Ne?!'
msarchet

4

Üçlü operatör gibi görünüyor:

return (_mywidget != NULL) ? _mywidget : new Widget();

3

Şahsen, okunabilirliğe bağlı olduğunu düşünüyorum. İlk örnekte, ??çeviriler "Orada mısınız ??

İkinci örnekte, ??!açıkça WTF olduğunu ve programcı için hiçbir şey ifade etmiyor .... nesne yok, bu yüzden ben 5 elde edeceğiz bu yüzden özelliği alamıyorum. Bu bile ne anlama geliyor? 5 nedir? 5'in iyi bir değer olduğu sonucuna nasıl ulaşabiliriz?

Kısacası, ilk örnek mantıklı ... orada değil, yeni . İkincisi, tartışmaya açık.


2
Eh, gerçeği görmezden gelmek zorundasın ??! mevcut değil. Hayal edin ??! yaygındı ve eğer kullanılmışsa buna dayalı kararlar verin.
whatsisname

3
Bu bana C ++ 'da sözde "WTF operatörü" hatırlatıyor (bu gerçekten işe yarıyor (foo() != ERROR)??!??! cerr << "Error occurred" << endl;.)
Tamás Szelei

@whatsisname, alınan karar için uygun olduğu gerçeğine daha çok yansımıştır. Orada olmadığı için bir nesne yaratmak mantıklı. Okuyucuya araçlar şey bir de alınamıyor çünkü bir arbituary değeri atamak için mülkiyet şey, gerçekten de bir WTF senaryodur.
Moo-Juice

Sanırım benim örneğimi yakaladın. Belki 0 5'ten daha iyidir. Belki özellik bir nesnedir, bu yüzden _mywidget null olursa, yeni bir foodle () döndürmek istersiniz. Tamamen katılmıyorum ?? daha okunabilir ??! rağmen :)
Ben Fulton

@Ben, Operatörün kendisine odaklanmanın sorunuza çok fazla borç vermediğini kabul etsem de, programcının algısına ve bu keyfi olana paralel bir çizim yapıyorum 5. Gerçekten böyle bir şey yapmak zorunda olduğunuz daha fazla bir sorun olduğunu düşünüyorum, ancak ilk örneğinizde, özellikle önbellek yöneticileri gibi şeylerde ihtiyaç oldukça açıktır.
Moo-Juice

2

Sanırım insanlar geri döndüğünüz "5" de çok fazla yakalanıyor ... belki 0 daha iyi olurdu :)

Her neyse, bence sorun ??!aslında tek başına bir operatör değil. Bunun ne anlama geldiğini düşünün:

var s = myString ??! "";

Bu durumda, bir anlam ifade etmez: yalnızca sol taraftaki işlenen bir mülk erişimcisi ise mantıklıdır. Ya da bunun hakkında:

var s = Foo(myWidget.Length) ??! 0;

Orada bir özellik erişimci, ama yine de (eğer mantıklı sanmıyorum myWidgetolduğunu null, ortalama biz demiyoruz bunu yapar Foo()hiç?), Ya da bu sadece bir hatadır?

Bence sorun dilde olduğu gibi doğal olarak da ??uymuyor.


1

Birisi bunu sizin için yapacak bir yardımcı sınıf yaratmıştı. Ama bulamıyorum. Ne buldum MSDN Forumlar benzer bir şeydi (ikinci cevaba bakınız).

Küçük bir çalışma ile, örnek çağrılarını desteklemeyen yöntem çağrılarını ve diğer ifadeleri değerlendirmek için genişletebilirsiniz. Ayrıca, varsayılan bir değeri kabul edecek şekilde genişletebilirsiniz.


1

Nereden geldiğini anlıyorum. Sanki herkes verdiğiniz örnekle akselin etrafına sarılıyor gibi görünüyor. Sihirli sayıların kötü bir fikir olduğunu kabul etsem de, belirli mülkler için boş bir coallescing operatörünün eşdeğeri için bir kullanım olurdu.

Örneğin, bir haritaya bağlı nesneleriniz var ve bunların doğru yükseklikte olmasını istiyorsunuz. DTED haritalarının verilerinde delikler olabilir, bu nedenle boş bir değere ve -100 ila ~ 8900 metre gibi bir aralıktaki değerlere sahip olmak mümkündür. Şunlar boyunca bir şeyler isteyebilirsiniz:

mapObject.Altitude = mapObject.Coordinates.DtedAltitude ?? DEFAULT_ALTITUDE;

Bu durumda null coallescing operatörü, Koordinatlar henüz ayarlanmadıysa veya Koordinatlar nesnesi o konum için DTED verilerini yükleyemediğinde varsayılan yüksekliği dolduracaktır.

Bunu çok değerli görüyorum, ancak neden yapılmadığına dair spekülasyonum derleyici karmaşıklığıyla sınırlı. Davranışın bu kadar öngörülebilir olmayabileceği bazı durumlar olabilir.


1

Derin yuvalanmış ile uğraşmadığınızda bunu kullandım (C # 6'da tanıtılan boş birleştirici işleçten önce). Benim için oldukça açık, ama belki de buna alışık olduğum için, diğer insanlar kafa karıştırıcı bulabilirler.

return ( _mywidget ?? new MyWidget() {length = defaultLength}).Length;

Tabii ki, bu her zaman geçerli değildir, çünkü bazen erişmeniz gereken mülk doğrudan ayarlanamaz veya nesnenin inşası pahalı olduğunda, diğer nedenlerin yanı sıra.

Başka bir alternatif ise NullObject modelini kullanmaktır . Sınıfın mantıklı varsayılan değerlerle tek bir statik örneğini tanımlarsınız ve bunun yerine bunu kullanırsınız.

return ( _mywidget ?? myWidget.NullInstance).Length;

0

Sihirli sayılar genellikle kötü bir koku. 5 rasgele bir sayı ise, daha açık bir şekilde belgelenmesi için onu daha iyi hecelemek daha iyidir. Bence bir istisna, belirli bir bağlamda varsayılan değerler olarak hareket eden bir değerler koleksiyonunuz varsa.

Bir nesne için varsayılan değerler kümeniz varsa, varsayılan bir singleton örneği oluşturmak için onu alt sınıflandırabilirsiniz.

Şuna benzer: return (myobj ?? default_obj).


0

Length özelliği genellikle bir değer türüdür, bu nedenle null olamaz, bu nedenle null birleştirme operatörü burada bir anlam ifade etmez.

Ancak bunu, referans türü olan bir özellikle yapabilirsiniz, örneğin: var window = App.Current.MainWindow ?? new Window();


Örnek, Current null olursa durumunuzda ne olacağını düşünmeye çalışmaktır. Örneğin sadece çökecekti ... ancak yanlış yönlendirme zincirinin herhangi bir yerinde boşluğa sahip olabilecek bir operatöre sahip olmak kullanışlı olurdu.
Mir

-1

Daha önce benzer bir fikri olan birini gördüm, ancak çoğu zaman yeni değeri null alanına da atamak istersiniz, örneğin:

return _obj ?? (_obj = new Class());

bu nedenle fikir ??ve =atamayı şu şekilde birleştirmekti :

return _obj ??= new Class();

Bunun ünlem işareti kullanmaktan daha mantıklı olduğunu düşünüyorum.

Bu fikir benim değil ama gerçekten beğendim :)


1
Zavallı örneğin kurbanı mısın? Örneğiniz return _obj ?? new Class();burada kısaltılmayacak şekilde kısaltılabilir ??=.
Matt Ellen

@ Matt Ellen yanlış anladın. Ödev amaçlanmıştır . Farklı bir alternatif öneriyorum. OP'nin istediği gibi değil, ama aynı derecede yararlı olacağına inanıyorum.
chakrit

2
bir değer döndürmek üzereyseniz, ödevi neden istiyorsunuz?
Matt Ellen

yavaş-başlatma?
chakrit
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.