2010-04-06 13 views
22

Mam proste kodu mały fragment, który jest frustrujące mnie:C# Operator warunkowy Nie oświadczenie?

HashSet<long> groupUIDs = new HashSet<long>(); 
groupUIDs.Add(uid)? unique++ : dupes++; 

w czasie kompilacji, to generuje błąd:

Only assignment, call, increment, decrement, and new object expressions can be used as a statement

HashSet.Add udokumentowaną powrócić bool, więc trójskładnikowej (?) Operator powinien zadziałać, i wygląda to na całkowicie zgodny z prawem sposób śledzenia liczby unikatowych i zduplikowanych elementów dodawanych do zestawu mieszającego.

Po sformatowaniu go jako "if-then-else" działa poprawnie.

Czy ktoś może wyjaśnić błąd i czy istnieje sposób, aby to zrobić jako prosty operator trójskładnikowy?

+1

Preferuję zamiast tego statemnet. Zmienna dummy assign, którą sugerują niektóre odpowiedzi, tylko wprowadza zamieszanie. –

+4

Należy również zwrócić uwagę, że ternaries są zwykle używane do wybierania wartości, a nie wybierania akcji. W twoim przypadku wybierasz, czy chcesz zwiększyć jedną z dwóch wartości. Tak więc w sensie bardziej semantycznym można użyć znaku "jeśli", ponieważ wybieramy akcję. – AaronLS

Odpowiedz

19

Zgodnie z komunikatem o błędzie operator trójargumentowy nie może być używany jako instrukcja. trzeba by zrobić coś takiego, aby włączyć go do przypisania:

int dummy = groupUIDs.Add(uid)? unique++ : dupes++; 

Mając na uwadze powyższe, polecam po prostu użyć if-then-else. Jest mniej kłopotliwy, ponieważ nie wiąże się z tworzeniem "magicznych" zmiennych manekinowych ...

+1

Wydaje się, że napraw to. W C nie ma nic złego w samodzielnym trójskładniku, który nic nie robi. Najwyraźniej nie jest to prawdą w języku C#. Dzięki. – abelenky

+9

Lub użyj operatora if zamiast operatora trójskładnikowego zamiast przypisywania wartości zmiennej bezużytecznej w celu zapewnienia chłodzenia kodu i utraty czytelności. – ANeves

+1

w pełni sformatowana instrukcja if pobiera 8 wierszy z dodatkowym poziomem wcięcia. To wydaje się ogromnym marnotrawstwem dla tak prostej operacji. Czuję się wyjątkowo komfortowo z potrójnym programistą C/C++ i nie widzę żadnego fajnego czynnika lub boli czytelność. – abelenky

4

Kompilator nie narzeka na Add narzeka na fakt, że wyrażenie warunkowe nie jest kompletnym stwierdzeniem.

Niektóre języki (np. JavaScript) pozwalają na użycie wyrażenia warunkowego w logice gałęzi, tak jak tutaj, ale C# wymaga przypisania wyniku wyrażenia warunkowego do zmiennej. Po przypisaniu wyniku wyrażenia wykonano pełną instrukcję, a kompilator jest zadowolony.

+4

Właściwie to narzeka na operatora trójskładnikowego. –

+0

@Andrew Czy nie uważa się ich za przyrost, który jest wymieniony w komunikacie o błędzie jako ważne stwierdzenie? – AaronLS

+0

@Merhdad - Tak, masz rację - naprawiam to teraz. –

7

Nie ustawiasz wartości wyniku trójskładnikowego na nic, dlatego.

HashSet<long> groupUIDs = new HashSet<long>(); 
int count = groupUIDs.Add(uid)? unique++ : dupes++; 
5

Operator trójskładnikowy nie jest instrukcją. Tak, to nie może być stosowany samodzielnie w instrukcji - to odpowiednik pisania

"something that is not a statement"; 

Aby wyjaśnić, należy wyjąć i użyć operatora potrójny if.

+0

Co najmniej w C i C, jest to całkowicie poprawna (choć bez skutków ubocznych) instrukcja. Najwyraźniej nie jest to prawdą w języku C#. Okazuje się, że właściwą odpowiedzią jest przypisanie manekina jako @sth. – abelenky

+0

To jest świetne wyjaśnienie, ponieważ jeśli pomyślisz o tym, jak działa trójskładnik, ocenia on jedną wartość, wartość wybraną z dwóch opcji. Tak więc po ocenie jest to jak pisanie instrukcji, która jest wartością 'unique;' (po inkrementacji), lub 'dupes;' co byłoby czymś w stylu '12345;' które nie byłoby poprawnym stwierdzeniem, ponieważ jest po prostu samotna liczba całkowita. – AaronLS

+1

@AaronLS: Po pierwsze, wartość unikalnego PRIORa wzrasta, a nie po. Po drugie, w wielu językach posiadanie samotnej liczby całkowitej jest całkowicie poprawne. C# różni się pod tym względem. – abelenky

0

Jeśli to nie jest akceptowalne, dlaczego linia ma być? Po prostu użyj instrukcji if :-)

 bool b = false; 
     b?callB():callA(); 
1

gmcalab i sr pt mają rację; operator trójskładnikowy ma dać ci wynik, tak jak 1 + 1 daje . Nie można po prostu napisać:

1 + 1;

Zamieszanie w tym miejscu (myślę) polega na tym, że myślisz o operatorze trójskładnikowym, jak to jest funkcją.

2

Musisz użyć wartości z operatora potrójnego dla czegoś ...

HashSet<long> groupUIDs = new HashSet<long>(); 
int newCount = groupUIDs.Add(uid)? unique++ : dupes++; 

lub - wykorzystanie if

HashSet<long> groupUIDs = new HashSet<long>(); 
if (groupUIDs.Add(uid)) 
    unique++; 
else 
    dupes++; 
1

description z potrójnego operatora w odniesieniu językowej mówi, że

If condition is true, first expression is evaluated and becomes the result; if false, the second expression is evaluated and becomes the result.

Wygląda trójoperandowy mogą być używane tylko w kontekście przydziału, chociaż odniesienie do języka nie określa go explicity. Nie wykonujesz zadania związanego z wynikiem.

Moim zdaniem, ponowne napisanie jako if/else byłoby bardziej przejrzyste.

+0

Nie musi to być zadanie - możesz na przykład przekazać je innej metodzie. –

+0

Masz rację - spieszyłem się i moje sformułowanie było zbyt luźne. –

16

Jak zauważyli inni, operator warunkowy nie jest wyrażeniem oświadczenia prawnego. (Wyrażenia wyrażenia prawnego to przypisania, wywołania, inkrementy, dekrementy i konstrukcje.)

Istnieje jednak również problem stylistyczny. Moim zdaniem wyrażeń powinny być przydatne dla ich wartości, a instrukcje powinny być przydatne dla ich skutków ubocznych. To, na co natrafiłeś, to to, że masz wyrażenie, które jest użyteczne tylko ze względu na efekt uboczny, a to jest nieprzyjemny zapach kodu.

Masz efekt uboczny, więc użyj instrukcji warunkowej zamiast wyrażenia warunkowego.

+1

Z szacunku dla @EricLippert, zmienię go na wyrażenie warunkowe, jeśli-else. Kolejny krok w górę krzywej uczenia się od C do C#. – abelenky

+8

@abelenky: Jestem zaszczycony, ale proszę, nie rób tego ze względu na mnie. Zrób to dla dobra przyszłych ludzi, którzy muszą zachować twój kod. :-) –

Powiązane problemy