Der folgende Code ist falsch (siehe ideone ):
public class Test
{
public static void Main()
{
int j = 5;
(j++); // if we remove the "(" and ")" then this compiles fine.
}
}
Fehler CS0201: Nur Anweisungen für Zuweisung, Aufruf, Inkrementieren, Dekrementieren, Warten und neue Objekte können als Anweisung verwendet werden
- Warum wird der Code kompiliert, wenn wir die Klammern entfernen?
- Warum wird nicht mit den Klammern kompiliert?
- Warum wurde C # so entworfen?
c#
syntax
expression
language-design
parentheses
user10607
quelle
quelle
Antworten:
Ich werde mein Bestes geben.
Wie andere Antworten angemerkt haben, erkennt der Compiler hier, dass ein Ausdruck als Anweisung verwendet wird . In vielen Sprachen - C, JavaScript und vielen anderen - ist es völlig legal, einen Ausdruck als Aussage zu verwenden.
2 + 2;
ist in diesen Sprachen legal, obwohl dies eine Aussage ist, die keine Wirkung hat. Einige Ausdrücke sind nur für ihre Werte nützlich, einige Ausdrücke sind nur für ihre Nebenwirkungen nützlich (z. B. ein Aufruf einer Methode zur Rückgabe von Leeren) und einige Ausdrücke sind leider für beide nützlich. (Wie Inkrement.)Punkt ist: Aussagen, die nur aus Ausdrücken bestehen, sind mit ziemlicher Sicherheit Fehler, es sei denn, diese Ausdrücke werden normalerweise als nützlicher für ihre Nebenwirkungen angesehen als ihre Werte . C # -Designer wollten einen Mittelweg finden, indem sie Ausdrücke zuließen, die allgemein als Nebenwirkungen angesehen wurden, während diejenigen, die normalerweise auch als nützlich für ihre Werte angesehen werden, nicht zugelassen wurden. Die in C # 1.0 identifizierten Ausdrücke waren Inkremente, Dekremente, Methodenaufrufe, Zuweisungen und etwas kontrovers diskutierte Konstruktoraufrufe.
ASIDE: Normalerweise wird eine Objektkonstruktion als für den Wert verwendet angesehen, den sie erzeugt, nicht für den Nebeneffekt der Konstruktion. Meiner Meinung nach ist das Zulassen
new Foo();
eine Fehlfunktion. Insbesondere habe ich dieses Muster im realen Code gesehen, der einen Sicherheitsmangel verursacht hat:Es kann überraschend schwierig sein, diesen Fehler zu erkennen, wenn der Code kompliziert ist.
Der Compiler erkennt daher alle Anweisungen, die aus Ausdrücken bestehen, die nicht in dieser Liste enthalten sind. Insbesondere werden Ausdrücke in Klammern als genau das identifiziert - Ausdrücke in Klammern. Sie sind nicht auf der Liste der "als Anweisungsausdrücke zugelassen" aufgeführt, daher sind sie nicht zulässig.
All dies dient einem Entwurfsprinzip der C # -Sprache. Wenn Sie getippt haben, haben
(x++);
Sie wahrscheinlich etwas falsch gemacht . Dies ist wahrscheinlich ein Tippfehler fürM(x++);
oder eine gerechte Sache. Denken Sie daran, dass die Haltung des C # -Compilerteams nicht lautet: " Können wir einen Weg finden, wie dies funktioniert? " Die Haltung des C # -Compilerteams lautet: " Wenn plausibler Code wie ein wahrscheinlicher Fehler aussieht, informieren wir den Entwickler. " C # -Entwickler mögen diese Einstellung.Nun, alles in allem gibt es tatsächlich einige seltsame Fälle, in denen die C # -Spezifikation impliziert oder direkt besagt , dass Klammern nicht zulässig sind, der C # -Compiler sie jedoch trotzdem zulässt. In fast allen diesen Fällen ist die geringfügige Diskrepanz zwischen dem angegebenen Verhalten und dem zulässigen Verhalten völlig harmlos, sodass die Compiler-Autoren diese kleinen Fehler nie behoben haben. Über diese können Sie hier lesen:
Gibt es einen Unterschied zwischen return myVar und return (myVar)?
quelle
... ? ... : ...
, wo der Fixif
/else
stattdessen verwendet werden soll.)contineu;
.try { new Foo(null); } catch (ArgumentNullException)...
aber offensichtlich sind diese Situationen per Definition kein Produktionscode. Es erscheint vernünftig, einen solchen Code so zu schreiben, dass er einer Dummy-Variablen zugewiesen wird.In der C # -Sprachspezifikation
Wenn Sie eine Anweisung in Klammern setzen, wird ein neuer sogenannter Ausdruck in Klammern erstellt. Aus der Spezifikation:
Da Ausdrücke in Klammern nicht als gültige Ausdrucksanweisung aufgeführt sind, handelt es sich nicht um eine gültige Anweisung gemäß der Spezifikation. Warum sich die Designer für diese Vorgehensweise entschieden haben, ist unklar, aber ich wette, dass Klammern keine nützliche Arbeit leisten, wenn die gesamte Aussage in Klammern steht:
stmt
und(stmt)
genau gleich sind.quelle
OP
fragt nichts nach dem Sprachdesign. Er will nur wissen, warum das ein Fehler ist. Die Antwort lautet: weil es keine gültige Aussage ist .Weil die Klammern um
i++
einen Ausdruck erstellen / definieren .. wie in der Fehlermeldung angegeben .. kann ein einfacher Ausdruck nicht als Anweisung verwendet werden.Warum wurde die Sprache so entworfen? um Fehler zu vermeiden, die irreführende Ausdrücke als Anweisungen haben und keine Nebenwirkungen wie den Code haben
Die zweite Zeile hat keine Auswirkung (aber Sie haben es möglicherweise nicht bemerkt). Aber anstatt dass der Compiler ihn entfernt (weil der Code nicht benötigt wird), fordert er Sie ausdrücklich auf, ihn zu entfernen (damit Sie den Fehler bemerken) ODER ihn zu beheben, falls Sie vergessen haben, etwas einzugeben.
bearbeiten :
Um den Teil über Klammern klarer zu machen, werden Klammern in c # (neben anderen Verwendungszwecken wie Cast und Funktionsaufruf) verwendet, um Ausdrücke zu gruppieren und einen einzelnen Ausdruck zurückzugeben (Make der Unterausdrücke).
Auf dieser Codeebene sind nur Stamente erlaubt
Aber wenn Sie die Klammer verwenden, verwandeln Sie sie in einen Ausdruck
und das
ist nicht gültig, da der Compiler nicht sicherstellen kann, dass der Ausdruck als Nebeneffekt auftritt (nicht ohne dass das Problem beim Anhalten auftritt).
quelle
j
Variablen durch, oder?j++;
ist eine gültige Aussage, aber unter Verwendung der Klammern, die Sie sagenlet me take this stement and turn it into an expression
.. und Ausdrücke sind zu diesem Zeitpunkt im Code nicht gültig