Koşullu kullanmanın faydaları?: (Üçlü) operatör


101

Standart if-else ifadesinin aksine?: Operatörünün yararları ve dezavantajları nelerdir. Bariz olanlar:

Koşullu?: Operatör

  • Doğrudan değer karşılaştırmaları ve atamaları ile uğraşırken daha kısa ve daha özlü
  • İf / else yapısı kadar esnek görünmüyor

Standart If / Else

  • Daha fazla duruma uygulanabilir (işlev çağrıları gibi)
  • Genellikle gereksiz yere uzundur

Okunabilirlik, ifadeye bağlı olarak her biri için değişiyor gibi görünüyor. ?: Operatörüne ilk kez maruz kaldıktan sonra bir süre, tam olarak nasıl çalıştığını sindirmem biraz zaman aldı. Programcı olmayan birçok kişi ile çalıştığım için, mümkün olan her yerde kullanmanızı veya if / else'e bağlı kalmanızı önerir misiniz?


8
Zaten işin özünü anladın.
Byron Whitlock

1
@Nicholas Knight: OP'nin yapamayacağınız anlamına geldiğini tahmin ediyorum, örneğin SomeCheck() ? DoFirstThing() : DoSecondThing();- bir değer döndürmek için ifadeyi kullanmanız gerekir.
Dan Tao

6
Açık olduğu yerde kullanın , değilse if / else'e bağlı kalın. Kod netliği ana düşünceniz olmalıdır.
hollsk

8
Gördün mü '??' hala? Cidden, üçlülerin harika olduğunu düşünüyorsanız ...
pdr

3
+1, birçoklarının yaptığı gibi ona basitçe "üçlü operatör" demediği için. C # 'daki tek üçlü (tekli ve ikili) operatör olmasına rağmen, adı bu değil.
John M Gant

Yanıtlar:


122

Temel olarak, yalnızca sonuçta ortaya çıkan ifade son derece kısa olduğunda ve okunabilirlikten ödün vermeden if / else eşdeğerine göre özlülükte önemli bir artışı temsil ettiğinde kullanılmasını öneririm.

İyi örnek:

int result = Check() ? 1 : 0;

Kötü örnek:

int result = FirstCheck() ? 1 : SecondCheck() ? 1 : ThirdCheck() ? 1 : 0;

5
İyi karar, ama kayıt için bu "kesinlik".
mqp

6
@mquander, bundan emin misin? merriam-webster.com/dictionary/concise
Byron Whitlock

39
Her zaman basit bir tanesiyle başlıyorum ve tamamen okunamaz hale gelene kadar zamanla daha karmaşık hale getiriyorum.
Jouke van der Maas

9
İkinci örnekteki okunabilirlik, daha iyi biçimlendirme ile kolayca düzeltilebilir. Ancak, OP'nin önerdiği gibi, ayrıntıya karşı okunabilirlik ve kısalık söz konusudur.
Nathan Ernst

4
OP'nin sorusunun bir parçası değil, ancak not edilmesi gereken önemli returnolan, üçlü operasyonun sonucunun bir parçası olamayacağınız gerçeğidir . Örneğin: check() ? return 1 : return 0;çalışmayacak ama return check() ? 1 : 0;çalışacak. Programlamadaki bu küçük tuhaflıkları bulmak her zaman eğlencelidir.
CSS

50

Bu, hemen hemen diğer cevaplar tarafından kapsanmaktadır, ancak "bu bir ifade", bunun neden bu kadar yararlı olduğunu gerçekten açıklamıyor ...

C ++ ve C # gibi dillerde, bunları kullanarak yerel salt okunur alanları (bir yöntem gövdesi içinde) tanımlayabilirsiniz. Bu, geleneksel eğer / ise ifadesi ile mümkün değildir, çünkü salt okunur bir alanın değerinin bu tek ifade içinde atanması gerekir:

readonly int speed = (shiftKeyDown) ? 10 : 1;

şununla aynı değil:

readonly int speed;  
if (shifKeyDown)  
    speed = 10;    // error - can't assign to a readonly
else  
    speed = 1;     // error  

Benzer şekilde, diğer koda bir üçüncül ifade de gömebilirsiniz. Kaynak kodunu daha kompakt (ve bazı durumlarda daha okunabilir) yapmanın yanı sıra, üretilen makine kodunu daha kompakt ve verimli hale getirebilir:

MoveCar((shiftKeyDown) ? 10 : 1);

... aynı yöntemi iki kez çağırmaktan daha az kod üretebilir:

if (shiftKeyDown)
    MoveCar(10);
else
    MoveCar(1);

Tabii ki, aynı zamanda daha uygun ve özlü bir biçimdir (daha az yazma, daha az tekrarlama ve if / else içindeki kod parçalarını kopyalamak zorunda kalırsanız hata olasılığını azaltabilir). Bunun gibi temiz "yaygın kalıp" durumlarda:

object thing = (reference == null) ? null : reference.Thing;

... okumak / ayrıştırmak / anlamak (alıştıktan sonra) uzun soluklu if / else eşdeğerinden daha hızlıdır, bu nedenle daha hızlı 'grok' yapmanıza yardımcı olabilir.

Elbette, yararlı olması , her durumda kullanılacak en iyi şey olduğu anlamına gelmez . Bunu yalnızca anlamın açık olduğu (veya daha net hale getirildiği) kısa kod bitleri için kullanmanızı öneririm ?:- eğer onu daha karmaşık bir kodda kullanırsanız veya üçlü operatörleri iç içe geçirirseniz, kodu okumayı korkunç derecede zorlaştırabilir .


@JaminGrey "bu, sabit oluşturulduğunda 10 veya 1 olarak ayarlandığı anlamına gelmez." Şunu Do does ortalama o? Yanlış yorumlar, yeni C ++ programcıları için,
gidermeye

5
Bununla karşılaşacak gelecekteki okuyucular için, " const int speed = (shiftKeyDown)? 10: 1; ", bu, sabit ilk oluşturulduğunda 10 veya 1 olarak ayarlandığı anlamına gelir . Bu , her seferinde sabite erişildiğinde bir kontrol yapar. (Daha yeni bir C ++ programcısının kafası karışmışsa)
Jamin Gray

2
... ya da başka bir deyişle, a constsabittir, yani bildirildiği ifade çalıştırıldıktan sonra değiştirilemez.
Jason Williams

1
@JaminGrey. Olması gerekmiyor readonlymu? Her zaman const" derleme zamanında çözüldü ve nerede kullanılırsa kullanılsın satır içi" anlamına geldiğini düşündüm .
Nolonar

1
@ColinWiseman, bir değil örnek :? Nasıl göstermek için olabilir kullanılabilir. Bunu özellikle yapabildiğiniz için bunun herhangi bir özel durumda yapılacak "en iyi" şey olduğu anlamına gelmediğini özellikle belirtiyorum. Bunu çözmek için, okuyucunun kendileri için yararlı olabilecek bir durumla karşılaştıklarında beynini kullanması bekleniyor.
Jason Williams

14

Aksi takdirde çok sayıda yinelenen kodum olduğunda genellikle üçlü bir operatör seçerim.

if (a > 0)
    answer = compute(a, b, c, d, e);
else
    answer = compute(-a, b, c, d, e);

Üçlü bir operatörle bu, aşağıdaki şekilde gerçekleştirilebilir.

answer = compute(a > 0 ? a : -a, b, c, d, e); 

12
şahsen ben yapardım aVal = a > 0 ? a : -a; answer = compute(aVal,b,c,d,e);Özellikle b, c, dve eçok tedavi edilmesi gerekti.
corsiKa

10
Bu örnekte neden bir koşul kullanılıyor? Abs (a) alın ve compute () öğesini bir kez çağırın.
Kül

2
Evet, en iyi örneği ben yaratmadım. :)
Ryan Bright

Bir acemi için bu eşdeğer görünmüyor. Answer = compute (a> 0? A, b, c, d, e: -a, b, c, d, e) olması gerekmiyor muydu? ?
pbreitenbach

@pbreitenbach: yok - bu öncelik meselesi - ilk bağımsız değişken compute(...)olan a > 0 ? a : -1diğer tüm virgülle ayrılmış argümanlar ayrı değerlendirilir. Her neyse, ne yazık ki C ++, virgülle ayrılmış değerlerin "demetlerini" ele almak için sorunuzun öne sürdüğü gösterimden yoksundur, bu nedenle bile a > 0 ? (a, b, c, d, e) : (-a, b, c, d, e)yasadışıdır ve computekendisinde değişiklik olmadan çalışan çok benzer hiçbir şey yoktur .
Tony Delroy

12

Bir değişkeni, tanımlanmışsa istek içinde gönderilen bir değere veya değilse varsayılan bir değere ayarlamak istiyorsam, web geliştirme yaparken özellikle yararlı buluyorum.


3
Web geliştiricideki +1 varsayılan değerleri mükemmel bir örnektir, üçlü operatörü kullanmak için iyi bir yer
Byron Whitlock

11

Gerçekten harika bir kullanım:

x = foo ? 1 :
    bar ? 2 :
    baz ? 3 :
          4;

10
PHP'de buna dikkat edin, üçlü operatör PHP'de yanlış şekilde ilişkilendirir. Esasen, eğer fooyanlışsa, diğer testleri yapmadan her şey 4 olarak değerlendirilecektir.
Tom Busby

4
@TomBusby - Vay canına. Zaten PHP'den nefret eden biriyseniz, PHP'den nefret etmek için başka bir neden.
Todd Lehman

6

Koşullu operatör, aşağıdaki gibi kısa koşullar için mükemmeldir:

varA = boolB ? valC : valD;

Ara sıra kullanıyorum çünkü bir şeyi bu şekilde yazmak daha az zaman alıyor ... ne yazık ki, bu dallanma bazen kodunuza göz atan başka bir geliştirici tarafından gözden kaçabilir. Artı, kod genellikle o kadar kısa değildir, bu yüzden genellikle? ve: aşağıdaki gibi ayrı satırlarda:

doSomeStuffToSomething(shouldSomethingBeDone()
    ? getTheThingThatNeedsStuffDone()
    : getTheOtherThingThatNeedsStuffDone());

Bununla birlikte, if / else bloklarını kullanmanın en büyük avantajı (ve neden onları tercih ettiğimi), daha sonra gelip dala bazı ek mantık eklemenin daha kolay olmasıdır.

if (shouldSomethingBeDone()) {
    doSomeStuffToSomething(getTheThingThatNeedsStuffDone());
    doSomeAdditionalStuff();
} else {
doSomeStuffToSomething(getTheOtherThingThatNeedsStuffDone());
}

veya başka bir koşul ekleyin:

if (shouldSomethingBeDone()) {
    doSomeStuffToSomething(getTheThingThatNeedsStuffDone());
    doSomeAdditionalStuff();
} else if (shouldThisOtherThingBeDone()){
    doSomeStuffToSomething(getTheOtherThingThatNeedsStuffDone());
}

Sonuç olarak, şimdi sizin için kolaylık (kullanımı daha kısa:?) İle daha sonra sizin (ve diğerleri) için kolaylık ile ilgili. Bu bir yargı çağrısı ... ancak diğer tüm kod biçimlendirme sorunları gibi, tek gerçek kural tutarlı olmak ve kodunuzu korumak (veya derecelendirmek!) Zorunda olanlara görsel olarak nazik davranmaktır.

(tüm kod göz ile derlenmiştir)


5

Üçlü operatörü kullanırken, bunun bir ifade değil bir ifade olduğunu anlamanız gereken bir şey var.

Şema gibi işlevsel dillerde ayrım yoktur:

(eğer (> ab) ab)

Koşullu?: Operatör "if / else yapısı kadar esnek görünmüyor"

İşlevsel dillerde öyle.

Zorunlu dillerde programlama yaparken, tipik olarak ifadeleri kullandığım durumlarda (atama, koşullu ifadeler, vb.) Üçlü operatörü uygularım.


5

Yukarıdaki cevaplar geçerli olmakla birlikte, okunabilirliğin önemli olduğuna katılıyorum, dikkate alınması gereken 2 nokta daha var:

  1. C # 6'da ifade gövdeli yöntemlere sahip olabilirsiniz.

Bu, üçlü kullanmayı özellikle özlü hale getirir:

string GetDrink(DayOfWeek day) 
   => day == DayOfWeek.Friday
      ? "Beer" : "Tea";
  1. Örtük tür dönüştürme söz konusu olduğunda davranış farklılık gösterir.

Eğer türleri varsa T1ve T2her iki örtük dönüştürülebilir T, daha sonra aşağıda yapar değil iş:

T GetT() => true ? new T1() : new T2();

(derleyici üçlü ifade türünü belirlemek için çalışır, çünkü arasında bir dönüşüm vardır, T1ve T2.)

Öte yandan, aşağıdaki if/elsesürüm çalışıyor:

T GetT()
{
   if (true) return new T1();
   return new T2();
}

çünkü T1dönüştürülür Tve öyledirT2


5

Bazen bir bool değerinin atanmasının ilk bakışta okunmasını kolaylaştırabilir:

// With
button.IsEnabled = someControl.HasError ? false : true;

// Without
button.IsEnabled = !someControl.HasError;

4

Bir değer ayarlıyorsam ve bunun her zaman bir satır kod olacağını biliyorsam, genellikle üçlü (koşullu) operatörü kullanırım. Gelecekte kodumun ve mantığımın değişme şansı varsa, diğer programcılar için daha açık olduğu için bir if / else kullanıyorum.

Sizin için daha fazla ilgi çekici olabilir mi ? operatör .


4

Koşullu operatörün avantajı, bir operatör olmasıdır. Başka bir deyişle, bir değer döndürür. Yana ifbir ifadedir, bir değer döndüremez.


4

Üçlü (? :) operatörünün kullanımını basit tek satırlı if / else mantığıyla sınırlandırmanızı öneririm. Bu kalıba benzeyen bir şey:

if(<boolCondition>) {
    <variable> = <value>;
}
else {
    <variable> = <anotherValue>;
}

Kolayca şuna dönüştürülebilir:

<variable> = <boolCondition> ? <value> : <anotherValue>;

If / else if / else, nested if / else veya birden fazla satırın değerlendirilmesiyle sonuçlanan if / else dal mantığını gerektiren durumlarda üçlü operatör kullanmaktan kaçınırdım. Üçlü operatörün bu durumlarda uygulanması muhtemelen okunamayan, kafa karıştırıcı ve yönetilemez kodlarla sonuçlanacaktır. Bu yardımcı olur umarım.


2

Kullanmanın bazı performans avantajları vardır. örneğin operatör. MS Visual C ++, ancak bu gerçekten derleyiciye özgü bir şey. Derleyici, bazı durumlarda koşullu dalı gerçekten optimize edebilir.


2

Kendimi en çok kullandığım senaryo, değerleri varsayılan yapmak için ve özellikle de geri dönüşlerde

return someIndex < maxIndex ? someIndex : maxIndex;

Gerçekten hoş bulduğum tek yer burası ama onlar için hoşuma gidiyor.

Bir boole arıyorsanız, bu bazen yapılması gereken uygun bir şey gibi görünebilir:

bool hey = whatever < whatever_else ? true : false;

Çünkü okumak ve anlamak çok kolay, ancak bu fikir her zaman daha bariz olan için fırlatılmalıdır:

bool hey = (whatever < whatever_else);

2

Aynı koşulda birden fazla şubeye ihtiyacınız varsa, bir if kullanın:

if (A == 6)
  f(1, 2, 3);
else
  f(4, 5, 6);

Farklı koşullara sahip birden fazla dala ihtiyacınız varsa, ifade sayısı kartopu oluşturacaksa, üçlüyi kullanmak isteyeceksiniz:

f( (A == 6)? 1: 4, (B == 6)? 2: 5, (C == 6)? 3: 6 );

Ayrıca, başlatmada üçlü operatörü kullanabilirsiniz.

const int i = (A == 6)? 1 : 4;

Bunu if ile yapmak çok dağınıksa:

int i_temp;
if (A == 6)
   i_temp = 1;
else
   i_temp = 4;
const int i = i_temp;

İlklendirmeyi if / else içine koyamazsınız çünkü kapsamı değiştirir. Ancak referanslar ve const değişkenleri yalnızca başlatma sırasında bağlanabilir.


2

Üçlü operatör bir rvalue içine dahil edilebilir, oysa eğer-then-else olamaz; öte yandan, eğer-ise-ise döngüleri ve diğer ifadeleri çalıştırabilirken, üçlü operatör yalnızca (muhtemelen void) r değerlerini çalıştırabilir.

İlgili bir notta, && ve || operatörler, if-then-else ile uygulanması daha zor olan bazı yürütme modellerine izin verir. Örneğin, birinin çağrılması gereken birkaç işlevi varsa ve bunlardan herhangi biri başarısız olursa bir kod parçasını yürütmek isterse, && operatörü kullanılarak güzelce yapılabilir. Bunu o operatör olmadan yapmak ya fazlalık kod, bir goto ya da fazladan bir bayrak değişkeni gerektirecektir.


1

İle C # 7 , yeni kullanabilirsiniz ref halk ref uyumlu değişkenlerin koşullu atama basitleştirmek için mevcuttur. Yani şimdi sadece şunları yapamazsınız:

int i = 0;

T b = default(T), c = default(T);

// initialization of C#7 'ref-local' variable using a conditional r-value⁽¹⁾

ref T a = ref (i == 0 ? ref b : ref c);

... ama aynı zamanda son derece harika:

// assignment of l-value⁽²⁾ conditioned by C#7 'ref-locals'

(i == 0 ? ref b : ref c) = a;

Kod Bu çizgi değerini verir abirine bya da cdeğerine bağlı olarak, i.



Notlar
1. r-değeri , atamanın sağ tarafıdır, atanan değerdir.
2. l-değeri , bir atamanın sol tarafıdır, atanan değeri alan değişkendir.

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.