İki soru işareti birlikte C # ne anlama geliyor?


1629

Bu kod satırı boyunca koştu:

FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();

İki soru işareti ne anlama geliyor, bir tür üçlü operatör mü? Google'a bakmak zor.


50
Kesinlikle üçlü bir operatör değil - sadece iki işlenen var! O (koşullu operatör gibi biraz olan üçlü) ama boş kaynaştırma operatör ikili operatörüdür.
Jon Skeet

90
Bunu, olası işverenin C # yeteneklerim hakkında daha önce şüphelerini dile getirdiği bir röportajda açıkladım, çünkü Java'yı bir süredir profesyonel olarak kullanıyordum. Daha önce duymamışlardı ve bundan sonra C # ile olan aşinalıkımı sorgulamamışlardı :)
Jon Skeet

77
@Jon Skeet Beatles'ı geri çeviren adamdan bu yana destansı bir başarısızlık olmadı. :-) Şu andan itibaren iç kitabınızda yazılı SO profilinize bir url bağlantısı içeren kitabınızın bir kopyasını gönderin.
Iain Holder

6
IainMH: Ne 's değerinde için, ben olmasaydı oldukça henüz kitap yazmaya başladı. (Ya da belki de sadece bölüm 1 üzerinde çalışıyordum - böyle bir şey.) Kuşkusuz benim için bir arama hızlı bir şekilde blogumu + makalelerimi
bulurdu

7
Re: q son cümle - gelecekteki ref için, SymbolHound bu tür bir şey için harika örn. Symbolhound.com/?q=%3F%3F&l=&e=&n=&u= [şüpheli kimseye bağlı değilim bir şekilde bulduğumda iyi bir araç gibi ...]
Steve Chambers

Yanıtlar:


2154

Bu boş birleştirme operatörü ve üçlü (hemen-if) operatörü gibi. Ayrıca bakınız ?? Operatör - MSDN .

FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();

genişler:

FormsAuth = formsAuth != null ? formsAuth : new FormsAuthenticationWrapper();

daha da genişler:

if(formsAuth != null)
    FormsAuth = formsAuth;
else
    FormsAuth = new FormsAuthenticationWrapper();

İngilizce'de, "Soldaki her şey boş değilse, bunu kullanın, aksi takdirde sağdaki olanı kullanın."

Bunların herhangi bir sayısını sırayla kullanabileceğinizi unutmayın. Aşağıdaki deyim olmayan ilk null adlı atar Answer#için Answer(bütün Cevapları boş ise o zaman Answernull):

string Answer = Answer1 ?? Answer2 ?? Answer3 ?? Answer4;

Ayrıca, yukarıdaki genişleme kavramsal olarak eşdeğerken, her bir ifadenin sonucu sadece bir kez değerlendirilir. Örneğin, bir ifade yan etkileri olan bir yöntem çağrısı ise bu önemlidir. (Bunu işaret ettiği için @Joey'e teşekkür ederiz.)


17
Bu belki zincirlemek için tehlikeli
Coops

6
@CodeBlend nasıl?
Ic.

68
@CodeBlend, tehlikeli değil. Eğer genişleyecek olsaydınız, bir dizi iç içe if / else deyiminiz olur. Sözdizimi sadece garip çünkü görmeye alışkın değilsiniz.
joelmdev

31
Boş dizeler için de
çalışsaydı

14
@Gusdor ??çağrışımsaldır, yani a ?? b ?? c ?? deşdeğerdir ((a ?? b) ?? c ) ?? d. "Atama işleçleri ve üçlü işleç (? :) sağ ilişkiseldir. Diğer tüm ikili işleçler ilişkisel kalır." Kaynak: msdn.microsoft.com/en-us/library/ms173145.aspx
Mark E. Haase

284

Başka hiç kimse sihirli kelimeleri henüz söylemediğinden: boş birleştirme operatörü . C # 3.0 dil spesifikasyonunun 7.12 bölümünde tanımlanmıştır .

Özellikle bir ifadede birden çok kez kullanıldığında çalışma şekli nedeniyle çok kullanışlıdır. Formun bir ifadesi:

a ?? b ?? c ?? d

anull değilse ifadenin sonucunu verecektir , aksi takdirde deneyin b, aksi takdirde deneyin c, aksi takdirde deneyin d. Her noktada kısa devre yapar.

Ayrıca, türünün dnull değeri yoksa, tüm ifadenin türü de null değeri yoktur.


2
Anlamını "boş birleştirme operatörü" ne kadar basitleştirdiğinizi seviyorum. Tüm ihtiyacım olan bu.
FrankO

2
Teğet ama ilişkili: Şimdi Swift'te, ama çok farklı: "Nil Coalescing Operator" geliştirici.apple.com/
Dan Rosenstark


27

Herkese teşekkürler, burada MSDN sitesinde bulduğum en kısa açıklama:

// y = x, unless x is null, in which case y = -1.
int y = x ?? -1;

4
Bu önemli bir yönü var ?? operatör - sıfırlanabilir türlerle çalışmaya yardımcı olmak için tanıtıldı. Örneğin, "x", "int?" Türündedir. (Null <int>).
Drew Noakes

9
Boş birleştirme operatörün ikinci terim olmayan null ise @vitule no, daha sonra sonuç NULL olmayan (ve -1sadece düz intolmayan null).
Suzanne Dupéron

Gerçekten böyle çalışmasını dilerdim. Bunu her zaman yapmak istiyorum, ancak kullanamadığım değişken nullable tipi olmadığından yapamıyorum. Coffeescript y = x çalışır? -1
PandaWood

@PandaWood Aslında yapabilirsiniz. Eğer xtiptedir int?, ancak ytiptedir int, yazabilirsiniz int y = (int)(x ?? -1). Bu ayrıştırmak olacak xbir etmek intDeğilse nullveya atamak -1için yeğer xolduğunu null.
Johan Wintgens

21

??değer null olduğunda boş değer türü için bir değer sağlamak için oradadır. Yani, formAuth null olursa, yeni FormsAuthenticationWrapper () döndürür.


19

resim açıklamasını buraya girin

İki soru işareti (??) bir Coalescing operatörü olduğunu gösterir.

Birleştirme operatörü bir zincirden ilk NON-NULL değerini döndürür. Her şeyi pratik olarak gösteren bu youtube videosunu görebilirsiniz .

Ama videonun söylediklerine daha fazlasını ekleyeyim.

İngilizcenin birleşmesinin anlamını görürseniz “birlikte konsolide” yazıyor. Örneğin, dört dizeyi zincirleyen basit bir birleştirme kodu.

Yani eğer str1olduğunu nullo çalışacağız str2eğer str2olduğunu nullo çalışacağız str3ve bu yüzden boş olmayan bir değere sahip bir dize bulana kadar üzerinde.

string final = str1 ?? str2 ?? str3 ?? str4;

Basit bir deyişle, Birleştirme operatörü bir zincirden ilk NON-NULL değerini döndürür.


Bu açıklamayı seviyorum çünkü bir diyagramı var ve son cümle bunu basit terimlerle açıklıyor! Kullanımımdaki güvenimi anlamayı ve arttırmayı kolaylaştırır. Teşekkürler!
Joshua K

14

Üçlü operatör için kısa el.

FormsAuth = (formsAuth != null) ? formsAuth : new FormsAuthenticationWrapper();

Veya üçlü yapmayanlar için:

if (formsAuth != null)
{
  FormsAuth = formsAuth;
}
else
{
  FormsAuth = new FormsAuthenticationWrapper();
}

3
Sadece "üçlü" nin yazımını düzelttim, ama gerçekten demek istediğin operatör şartlı operatör. C #'daki tek üçlü operatör olur, ancak bir noktada başka bir tane ekleyebilirler, bu noktada "üçlü" belirsiz olacak, ancak "koşullu" olmayacak.
Jon Skeet

Üçlü (koşullu) operatörle yapabileceğiniz bir şey için kestirme yol . Uzun formunuzda, hem test ( != null) hem de ikincisi formsAuth(sonra ?) değiştirilebilir; null birleştirme formunda, her ikisi de sağladığınız değerleri örtük olarak alır.
Bob Sammers

12

Ruby'ye aşina iseniz, ||=C # 'a benzer ??. İşte biraz Ruby:

irb(main):001:0> str1 = nil
=> nil
irb(main):002:0> str1 ||= "new value"
=> "new value"
irb(main):003:0> str2 = "old value"
=> "old value"
irb(main):004:0> str2 ||= "another new value"
=> "old value"
irb(main):005:0> str1
=> "new value"
irb(main):006:0> str2
=> "old value"

Ve C # ile:

string str1 = null;
str1 = str1 ?? "new value";
string str2 = "old value";
str2 = str2 ?? "another new value";

4
x ||= ydesugarlar gibi bir şeye x = x || y, yani Ruby'deki ??ovaya daha benzer ||.
qerub

6
Not o ??sadece umurunda hakkında null, oysa ||çoğu dilde olduğu gibi Ruby operatör, fazlasıdır null, falsebir değere sahip bir boolean kabul edilebilir, ya da bir şey false(bazı dillerde örneğin ""). Bu iyi ya da kötü bir şey değil, sadece bir fark.
Tim S.

11

birleştirme operatörü

eşittir

FormsAuth = formsAUth == null ? new FormsAuthenticationWrapper() : formsAuth

11

Bu konuda tehlikeli bir şey yok. Aslında çok güzel. İstenirse varsayılan değer ekleyebilirsiniz, örneğin:

KOD

int x = x1 ?? x2 ?? x3 ?? x4 ?? 0;

1
Yani x1, x2, x3 ve x4 Nullable türleri olabilir, örnek: int? x1 = null;Doğru mu
Kevin Meredith

1
@KevinMeredith x1- x4null türleri OLMALIDIR: etkin, "sonucudur söylemek anlamsızdır 0eğer x4(muhtemelen alamaz bir değerdir" null). Burada "boş değer türü", hem boş değer değer türlerini hem de referans türlerini içerir. Zincirleme değişkenlerden biri veya daha fazlası (sonuncusu hariç) geçersiz kılınamazsa, derleme zamanı hatasıdır.
Bob Sammers

11

Çok sayıda cevaba doğru bir şekilde işaret ettiği gibi, "boş birleştirme operatörü" ( ?? ), bunun da kuzenini kontrol etmek isteyebileceğiniz "Boş Koşullu Operatör" ( ?. Veya ? [ ) birçok kez ??

Boş Koşullu Operatör

Üye erişimi ( ?. ) Veya dizin ( ? [ ) İşlemini gerçekleştirmeden önce null değerini sınamak için kullanılır . Bu işleçler, özellikle veri yapılarına inmek için null denetimleri işlemek için daha az kod yazmanıza yardımcı olur.

Örneğin:

// if 'customers' or 'Order' property or 'Price' property  is null,
// dollarAmount will be 0 
// otherwise dollarAmount will be equal to 'customers.Order.Price'

int dollarAmount = customers?.Order?.Price ?? 0; 

Eski yol olmadan ? ve ?? bunu yapmak

int dollarAmount = customers != null 
                   && customers.Order!=null
                   && customers.Order.Price!=null 
                    ? customers.Order.Price : 0; 

ki bu daha ayrıntılı ve hantaldır.


10

Sadece eğlence için (hepinizin C # guys ;-) olduğunu bilmek.

Bence yıllardır var olduğu Smalltalk kökenlidir. Orada şöyle tanımlanır:

Nesnede:

? anArgument
    ^ self

UndefinedObject (aka nil'in sınıfı):

? anArgument
    ^ anArgument

Bunun hem değerlendiren (?) Hem de değerlendirmeyen versiyonları (??) vardır.
Genellikle ihtiyaç duyulana kadar sıfır bırakılan tembel olarak başlatılan özel (örnek) değişkenler için getter yöntemlerinde bulunur.


ViewState öğesini bir UserControl öğesindeki bir özellikle kaydırma gibi görünür. Daha önce ayarlanmadıysa, yalnızca ilk almada başlat. =)
Seiti

9

Buradaki birleştirmeyi kullanarak değer elde etmenin bazı örnekleri verimsizdir.

Gerçekten istediğiniz şey:

return _formsAuthWrapper = _formsAuthWrapper ?? new FormsAuthenticationWrapper();

veya

return _formsAuthWrapper ?? (_formsAuthWrapper = new FormsAuthenticationWrapper());

Bu, nesnenin her seferinde yeniden oluşturulmasını önler. Özel değişken null olarak kalır ve her istekte yeni bir nesne oluşturulursa, bu yeni nesne oluşturulursa özel değişkenin atanmasını sağlar.


Is not ??kestirme değerlendirdi? yalnızca sıfır new FormsAuthenticationWrapper();ise değerlendirilir . _formsAuthWrapper
MSalters

Evet bütün mesele bu. Yöntemi yalnızca değişken null olduğunda çağırmak istersiniz. @MSalters
KingOfHypocrites

8

Not:

Bütün bu konu ve diğerleri okudum ama bu kadar kapsamlı bir cevap bulamıyorum.

Bununla tamamen "neden kullanılır? Ve ne zaman kullanılır? Ve nasıl kullanılır ??" tamamen anladım.

Kaynak:

Craig McMurtry tarafından Windows iletişim vakfı açıldı ISBN 0-672-32948-4

Null Değer Değerleri

Birinin, bir değer türünün bir örneğine bir değer atanıp atanmadığını bilmek istediği iki yaygın durum vardır. Birincisi, örneğin bir veritabanındaki bir değeri temsil ettiği zamandır. Böyle bir durumda, veritabanında bir değerin gerçekten bulunup bulunmadığını tespit etmek için örneği incelemek isteriz. Bu kitabın konusuyla daha ilgili olan diğer koşul, örneğin bazı uzak kaynaklardan alınan bir veri öğesini temsil ettiği zamandır. Yine, örnekten o veri öğesi için bir değerin alınıp alınmadığını belirlemek ister.

.NET Framework 2.0, bir değer türünün bir örneğine null atamak ve örneğin değerinin null olup olmadığını sınamak isteyen, bunun gibi durumlar sağlayan genel bir tür tanımı içerir. Bu genel tür tanımı, T yerine değer türleriyle değiştirilebilecek genel tür bağımsız değişkenlerini kısıtlayan System.Nullable'dır. System.Nullable öğesinden oluşturulan tür örneklerine null değeri atanabilir; aslında, değerleri varsayılan olarak boştur. Bu nedenle, System.Nullable öğesinden oluşturulan türlere nullable değer türleri denebilir. System.Nullable, Value değeri null değilse, kendisinden oluşturulan bir türün örneğine atanan değerin alınabileceği bir değer olan bir özelliğe sahiptir. Bu nedenle, bir kişi şunları yazabilir:

System.Nullable<int> myNullableInteger = null;
myNullableInteger = 1;
if (myNullableInteger != null)
{
Console.WriteLine(myNullableInteger.Value);
}

C # programlama dili, System.Nullable öğesinden oluşturulan türleri bildirmek için kısaltılmış bir sözdizimi sağlar. Bu sözdizimi kişinin kısaltmasına izin verir:

System.Nullable<int> myNullableInteger;

için

int? myNullableInteger;

Derleyici, bir kişinin nullable değer türünün değerini sıradan bir değer türüne şu şekilde atamasını engeller:

int? myNullableInteger = null;
int myInteger = myNullableInteger;

Null olabilecek değer türünün bu durumda gerçekte sahip olacağı null değerine sahip olabilmesi ve bu değerin sıradan bir değer türüne atanamaması nedeniyle bunu önler. Derleyici bu koda izin verse de,

int? myNullableInteger = null;
int myInteger = myNullableInteger.Value;

System.Nullable öğesinden oluşturulan tipe geçerli bir T değeri atanmamışsa, System.Nullable.Value özelliğine erişme girişimi geçersiz bir işlem olduğundan, ikinci ifade bir özel durumun atılmasına neden olur. durum.

Sonuç:

Bir boş değer türünün değerini sıradan bir değer türüne atamanın uygun bir yolu, boş değer değeri türüne geçerli bir T değerinin atanıp atanmadığını belirlemek için System.Nullable.HasValue özelliğini kullanmaktır:

int? myNullableInteger = null;
if (myNullableInteger.HasValue)
{
int myInteger = myNullableInteger.Value;
}

Başka bir seçenek de bu sözdizimini kullanmaktır:

int? myNullableInteger = null;
int myInteger = myNullableInteger ?? -1;

Buna, sıradan tamsayı myInteger'a atanmışsa, sonuncusuna geçerli bir tamsayı değeri atanmışsa, boş değerli tamsayı "myNullableInteger" değeri atanır; aksi takdirde, myInteger öğesine -1 değeri atanır.


1

Üçlü bir operatöre benzer şekilde çalışan bir boş birleştirme operatörüdür.

    a ?? b  => a !=null ? a : b 

Bunun bir başka ilginç yanı da, "Null olabilecek bir tür bir değer içerebilir ya da tanımsız olabilir" dir . Bu nedenle, boş olmayan bir değer türüne boş değer değeri atamaya çalışırsanız, derleme zamanı hatası alırsınız.

int? x = null; // x is nullable value type
int z = 0; // z is non-nullable value type
z = x; // compile error will be there.

Yani bunu kullanarak ?? Şebeke:

z = x ?? 1; // with ?? operator there are no issues

1
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();

eşittir

FormsAuth = formsAuth != null ? formsAuth : new FormsAuthenticationWrapper();

Ama bunun en güzel yanı, diğer insanların söylediği gibi onları zincirleyebilmeniz. Dokunulmayan tek şey, aslında bir istisna atmak için kullanabileceğinizdir.

A = A ?? B ?? throw new Exception("A and B are both NULL");

Her ne kadar soru operatörün ne olduğuna veya ne yaptığına dair bir açıklama aramasına rağmen, postanıza örnekler eklemeniz gerçekten harika.
TGP1994

1

??Operatör boş-kaynaştırma operatör denir. İşlenen boş değilse, soldaki işleneni döndürür; aksi takdirde sağ taraftaki işleneni döndürür.

int? variable1 = null;
int variable2  = variable1 ?? 100;

Set variable2değerine variable1eğer variable1boş değil; aksi takdirde 100 olarak variable1 == nullayarlayın variable2.


0

Diğerleri Null Coalescing Operatoroldukça iyi tanımladı . İlgilenenler için bunun kısaltılmış bir sözdizimi vardır (SO sorusu):

FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();

buna eşdeğerdir:

FormsAuth ??= new FormsAuthenticationWrapper();

Bazıları onu daha okunaklı ve özlü bulur.

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.