2010-04-06 14 views
22

Ho un semplice frammento di codice poco che mi è frustrante:Operatore condizionale C# non una dichiarazione?

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

In fase di compilazione, si genera l'errore:

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

HashSet.Add è documentato per restituire un bool, in modo che il ternario (?) l'operatore dovrebbe funzionare, e questo sembra un modo completamente legittimo per tracciare il numero di elementi unici e duplicati che aggiungo a un hash-set.

Quando lo riformatto come if-then-else, funziona correttamente.

Qualcuno può spiegare l'errore e se c'è un modo per farlo come un semplice operatore ternario?

+1

Preferisco invece lo statemnet. Il dummy assegna una variabile che alcune risposte suggeriscono aggiunge semplicemente confusione. –

+4

Nota anche i ternari sono solitamente usati per scegliere un valore, non scegliere un'azione. Nel tuo caso stai scegliendo se incrementare uno dei due valori. Quindi è più sensato semantico utilizzare un if-else poiché si sta scegliendo un'azione. – AaronLS

risposta

19

In base al messaggio di errore, l'operatore ternario non può essere utilizzato come istruzione. Si avrebbe bisogno di fare qualcosa di simile per trasformarlo in un incarico:

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

Detto questo, mi consiglia di utilizzare solo if-then-else. È meno confuso perché non comporta la creazione di variabili fittizie "magiche" ...

+1

Questo sembra aggiustalo. In C, non c'è nulla di sbagliato in un ternario autonomo che non fa nulla. Apparentemente questo non è vero in C#. Grazie. – abelenky

+9

Oppure utilizzare un if al posto dell'operatore ternario, invece di assegnare un valore a una variabile inutile a fini di raffreddamento del codice e di detrimento della leggibilità. – ANeves

+1

un'istruzione if completamente formattata richiede 8 righe con un livello di indentazione aggiuntivo. Sembra un enorme spreco per un'operazione così semplice. Sono estremamente a mio agio con ternario come programmatore C/C++, e non vedo alcun fattore di raffreddamento o mi fa male leggibilità. – abelenky

4

Il compilatore non si lamenta di Add, si lamenta del fatto che l'espressione condizionale non è un'istruzione completa.

Alcuni linguaggi (come JavaScript) consentono di utilizzare un'espressione condizionale alla logica di diramazione come si è fatto qui ma C# richiede di assegnare il risultato dell'espressione condizionale a una variabile. Una volta assegnato il risultato dell'espressione, hai fatto una dichiarazione completa e il compilatore è felice.

+4

In realtà, si lamenta dell'operatore ternario. –

+0

@Andrew Questi non dovrebbero essere considerati un incremento, che è indicato nel messaggio di errore come una dichiarazione valida? – AaronLS

+0

@ Merhad - Sì, hai ragione - lo sto sistemando ora. –

7

Non stai impostando il valore del risultato del ternario su qualsiasi cosa sia il motivo.

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

L'operatore ternario non è una dichiarazione. Quindi, non può essere usato da solo in un'istruzione - è l'equivalente di scrittura

"something that is not a statement"; 

Per chiarire, si dovrebbe prendere l'operatore ternario e utilizzare un caso.

+0

Almeno in C e C++, è un'affermazione perfettamente valida (anche se senza effetti collaterali). Apparentemente questo non è vero in C#. La risposta giusta è avere un compito fittizio come suggerito da @sth. – abelenky

+0

Questa è una grande spiegazione, perché se si pensa a come funziona un ternario, si valuta un singolo valore, il valore scelto tra le due opzioni. Quindi una volta valutato è proprio come scrivere l'istruzione che è il valore di 'unique;' (dopo essere stato incrementato), o 'dupes; 'che sarebbe qualcosa come' 12345; 'che non sarebbe una dichiarazione valida dal momento che è solo un numero intero. – AaronLS

+1

@AaronLS: Innanzitutto, il valore di PRIOR univoco da incrementare, non dopo. In secondo luogo, in molte lingue, avere un intero solo è perfettamente valido. C# è diverso in questo senso. – abelenky

0

Se questo non è accettabile, perché dovrebbe essere la tua linea? Basta usare una dichiarazione if :-)

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

gmcalab e sr pt hanno ragione; l'operatore ternario ha lo scopo di darti un risultato, proprio come 1 + 1 ti dà 2. Non si poteva semplicemente scrivere:

1 + 1;

La confusione qui (penso) è che stai pensando all'operatore ternario come se fosse una funzione.

2

È necessario utilizzare il valore dall'operatore ternario per qualcosa ...

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

o - l'utilizzo di un se

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

La description del operatore ternario in riferimento al linguaggio dice che

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

Sembra che il ternario può essere utilizzato solo nel contesto di incarico, sebbene il riferimento al linguaggio non lo dichiari esplicitamente. Non stai facendo un incarico sul risultato.

A mio parere, la riscrittura come se fosse altrimenti sarebbe più chiara.

+0

Non deve essere un compito: puoi passarlo ad un altro metodo, ad esempio. –

+0

Hai ragione - Ero di fretta e le mie parole erano troppo sciolte. –

16

Come altri hanno sottolineato, l'operatore condizionale non è un'espressione di dichiarazione legale. (Le espressioni della dichiarazione legale sono assegnazioni, chiamate, incrementi, decrementi e costruzioni.)

Tuttavia, anche qui c'è un problema stilistico. A mio parere, le espressioni dovrebbero essere utili per i loro valori e le dichiarazioni dovrebbero essere utili per i loro effetti collaterali. Quello che stai incontrando è che hai un'espressione che è utile solo per il suo effetto collaterale, e questo è un cattivo odore di codice.

Si ha un effetto collaterale, quindi utilizzare un'istruzione condizionale anziché un'espressione condizionale.

+1

Per rispetto a @EricLippert, lo cambierò in un'istruzione condizionale, if-else. Un altro passo avanti nella curva di apprendimento da C a C#. – abelenky

+8

@abelenky: Sono lusingato, ma per favore, non farlo per il mio bene. Fallo per il futuro delle persone che devono mantenere il tuo codice. :-) –

Problemi correlati