2010-04-06 14 views
22

ich ein einfaches kleines Codefragment, die mich ist frustrierend:C# Bedingter Operator Keine Aussage?

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

Beim Kompilieren erzeugt er den Fehler:

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

HashSet.Add dokumentiert ist ein bool zurück, so die ternäre (?) operator sollte funktionieren, und dies sieht wie eine völlig legitime Möglichkeit aus, die Anzahl der eindeutigen und doppelten Elemente zu verfolgen, die ich zu einem Hash-Set hinzufüge.

Wenn ich es als if-then-else neu formatiere, funktioniert es gut.

Kann jemand den Fehler erklären, und wenn es eine Möglichkeit gibt, dies als ein einfacher ternärer Operator zu tun?

+1

Ich bevorzuge stattdessen das if-StatMnet. Die Dummy-Zuweisungsvariable, die einige Antworten vorschlagen, fügt nur Verwirrung hinzu. –

+4

Auch Notiz ternärs werden normalerweise verwendet, um einen Wert zu wählen, wählen Sie keine Aktion. In Ihrem Fall wählen Sie, ob Sie einen von zwei Werten erhöhen möchten. Es macht also mehr semantischen Sinn, ein if-else zu verwenden, da Sie eine Aktion wählen. – AaronLS

Antwort

19

Laut der Fehlermeldung kann der ternäre Operator nicht als Anweisung verwendet werden. Sie müßten etwas tun, wie diese es in eine Zuordnung drehen:

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

Das, gesagt würde ich empfehlen, nur zu verwenden, wenn-then-else. Es ist weniger verwirrend, weil es nicht die Schaffung von "magischen" Dummy-Variablen beinhaltet ...

+1

Dies scheint repariere es. In C ist nichts falsch mit einem eigenständigen Ternär, das nichts tut. Anscheinend trifft das in C# nicht zu. Vielen Dank. – abelenky

+9

Oder verwenden Sie einen if anstelle des ternären Operators, anstatt einen Wert für eine nutzlose Variable aus Gründen der Code Coolness und Nachteil der Lesbarkeit zu vergeben. – ANeves

+1

Eine vollständig formatierte if-Anweisung benötigt 8 Zeilen mit einer zusätzlichen Einrückungsebene. Das scheint eine riesige Verschwendung für solch eine einfache Operation zu sein. Ich bin sehr komfortabel mit ternären als C/C++ - Programmierer, und sehe keinen cool-Faktor oder dass es Lesbarkeit verletzt. – abelenky

4

Der Compiler beklagt sich nicht über Add Es beschwert sich über die Tatsache, dass Ihr bedingter Ausdruck keine vollständige Aussage ist.

In einigen Sprachen (wie JavaScript) können Sie einen Verzweigungslogik-bedingten Ausdruck wie hier verwenden, aber C# erfordert, dass Sie das Ergebnis des bedingten Ausdrucks einer Variablen zuweisen. Sobald Sie das Ergebnis des Ausdrucks zugewiesen haben, haben Sie eine vollständige Anweisung erstellt und der Compiler ist glücklich.

+4

Eigentlich beschwert es sich über den ternären Operator. –

+0

@Andrew Wäre das nicht ein Inkrement, das in der Fehlermeldung als gültige Aussage erwähnt wird? – AaronLS

+0

@Merhdad - Ja, Sie haben Recht - ich bin dabei, es zu beheben. –

7

Sie setzen das Wertergebnis der Ternär nicht auf etwas, warum.

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

Der ternäre Operator ist keine Aussage. So kann es nicht allein in einer Anweisung verwendet werden - es ist das Äquivalent von

Schreiben
"something that is not a statement"; 

Um zu klären, sollten Sie den ternären Operator herausnehmen und verwenden eine if.

+0

In C und C++ zumindest, das ist eine vollkommen gültige (wenn auch ohne Nebenwirkungen) Aussage. Anscheinend trifft das in C# nicht zu. Es stellt sich heraus, dass die richtige Antwort eine Dummy-Zuweisung ist, wie @sth vorgeschlagen hat. – abelenky

+0

Dies ist eine großartige Erklärung, denn wenn Sie darüber nachdenken, wie ein ternäres System funktioniert, wird ein einzelner Wert ausgewertet, der Wert, der aus den beiden Optionen ausgewählt wird. Nach der Auswertung ist es also genau so wie das Schreiben der Anweisung, die den Wert von 'unique; '(nach Inkrementieren) oder' dupes; 'darstellt, was etwas wie' 12345;' wäre, was keine gültige Aussage wäre, da dies der Fall ist nur eine einzelne ganze Zahl. – AaronLS

+1

@AaronLS: Erstens wäre es der Wert von einzigartigen PRIOR zu inkrementieren, nicht nach. Zweitens ist in vielen Sprachen die Existenz einer einzelnen Ganzzahl absolut gültig. C# ist in dieser Hinsicht anders. – abelenky

0

Wenn das nicht akzeptabel ist, warum sollte Ihre Linie sein? Verwenden Sie einfach eine if-Anweisung :-)

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

gmcalab und sr pt haben Recht; der ternäre Operator soll Ihnen ein Ergebnis geben, genau wie 1 + 1 gibt Ihnen 2. Sie konnten nicht einfach schreiben:

1 + 1;

Die Verwirrung hier (denke ich) ist, dass Sie an den ternären Operator denken, als ob es eine Funktion ist.

2

Sie müssen den Wert aus dem ternären Operator für etwas verwenden ...

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

oder - Verwendung ein, wenn

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

Die description des ternären Operator in der Sprachreferenz sagt, dass

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

Es sieht aus wie das ternäre kann nur im Kontext verwendet werden der Zuordnung, obwohl die Sprachreferenz es nicht explizit angibt. Sie machen keine Zuweisung für das Ergebnis.

Meiner Meinung nach wäre das Umschreiben als if/else klarer.

+0

Es muss keine Zuweisung sein - Sie können es beispielsweise an eine andere Methode übergeben. –

+0

Sie haben Recht - ich hatte es eilig und meine Formulierung war zu locker. –

16

Wie andere darauf hingewiesen haben, ist der bedingte Operator kein Ausdruck für eine gültige Anweisung. (Die Ausdrücke der legalen Aussage sind Zuweisungen, Aufrufe, Inkremente, Dekremente und Konstruktionen.)

Allerdings gibt es auch hier ein stilistisches Problem. Meiner Meinung nach Ausdrücke sollten nützlich sein für ihre Werte und Aussagen sollten nützlich sein für ihre Nebenwirkungen. Was Sie erreichen, ist, dass Sie einen Ausdruck haben, der nur für seine Nebenwirkung nützlich ist, und das ist ein schlechter Code-Geruch.

Sie haben einen Nebeneffekt, verwenden Sie also eine bedingte Anweisung und nicht einen bedingten Ausdruck.

+1

In Bezug auf @EricLippert, ich werde es in eine bedingte Anweisung ändern, wenn sonst. Ein weiterer Schritt die Lernkurve von C nach C#. – abelenky

+8

@abelenky: Ich bin geschmeichelt, aber bitte, tu es nicht um meinetwillen. Tun Sie es für die zukünftigen Menschen, die Ihren Code pflegen müssen. :-) –