Le code suivant est erroné (voir sur ideone ):
public class Test
{
public static void Main()
{
int j = 5;
(j++); // if we remove the "(" and ")" then this compiles fine.
}
}
erreur CS0201: Seules les expressions d'affectation, d'appel, d'incrémentation, de décrémentation, d'attente et de nouvel objet peuvent être utilisées comme instruction
- Pourquoi le code se compile-t-il lorsque nous supprimons les parenthèses?
- Pourquoi ne compile-t-il pas avec les parenthèses?
- Pourquoi le C # a-t-il été conçu de cette façon?
c#
syntax
expression
language-design
parentheses
utilisateur10607
la source
la source
Réponses:
Je ferai de mon mieux.
Comme d'autres réponses l'ont noté, ce qui se passe ici, c'est que le compilateur détecte qu'une expression est utilisée comme instruction . Dans de nombreux langages - C, JavaScript et bien d'autres - il est parfaitement légal d'utiliser une expression comme une déclaration.
2 + 2;
est légal dans ces langues, même s'il s'agit d'une déclaration sans effet. Certaines expressions ne sont utiles que pour leurs valeurs, certaines expressions ne sont utiles que pour leurs effets secondaires (comme un appel à une méthode de retour void) et certaines expressions, malheureusement, sont utiles pour les deux. (Comme incrément.)Le fait est que les déclarations qui consistent uniquement en expressions sont presque certainement des erreurs à moins que ces expressions ne soient généralement considérées comme plus utiles pour leurs effets secondaires que leurs valeurs . Les concepteurs C # souhaitaient trouver un terrain d'entente, en autorisant les expressions généralement considérées comme ayant un effet secondaire, tout en refusant celles qui sont également généralement considérées comme utiles pour leurs valeurs. L'ensemble d'expressions qu'ils ont identifié dans C # 1.0 étaient des incréments, des décrémentations, des appels de méthode, des affectations et, de manière quelque peu controversée, des invocations de constructeur.
A part: On pense normalement qu'une construction d'objet est utilisée pour la valeur qu'elle produit, pas pour l'effet secondaire de la construction; à mon avis, permettre
new Foo();
est un peu une erreur. En particulier, j'ai vu ce modèle dans le code du monde réel qui a causé un défaut de sécurité:Il peut être étonnamment difficile de repérer ce défaut si le code est compliqué.
Le compilateur fonctionne donc pour détecter toutes les instructions qui consistent en des expressions qui ne figurent pas sur cette liste. En particulier, les expressions entre parenthèses sont identifiées comme cela - des expressions entre parenthèses. Ils ne figurent pas dans la liste des «expressions autorisées en tant qu'expressions d'instruction», donc elles sont interdites.
Tout cela est au service d'un principe de conception du langage C #. Si vous avez tapé,
(x++);
vous avez probablement fait quelque chose de mal . C'est probablement une faute de frappeM(x++);
ou quelque chose de juste. N'oubliez pas que l'attitude de l'équipe du compilateur C # n'est pas " pouvons-nous trouver un moyen de faire ce travail? " L'attitude de l'équipe du compilateur C # est " si le code plausible ressemble à une erreur probable, informons le développeur ". Les développeurs C # aiment cette attitude.Maintenant, tout ce que dit, il y a effectivement quelques cas bizarres où la spécification C # n'Évoquez ou énoncez pur et simple que les parenthèses ne sont pas autorisés , mais le compilateur C # leur permet de toute façon. Dans presque tous ces cas, la différence mineure entre le comportement spécifié et le comportement autorisé est totalement inoffensive, de sorte que les auteurs du compilateur n'ont jamais corrigé ces petits bogues. Vous pouvez en savoir plus ici:
Y a-t-il une différence entre return myVar et return (myVar)?
la source
... ? ... : ...
, où le correctif est d'utiliserif
/ à laelse
place.)contineu;
.try { new Foo(null); } catch (ArgumentNullException)...
mais évidemment, ces situations ne sont pas par définition du code de production. Il semble raisonnable qu'un tel code puisse être écrit pour être affecté à une variable factice.Dans la spécification du langage C #
Le fait de placer des parenthèses autour d'une instruction crée une nouvelle expression dite entre parenthèses. De la spécification:
Étant donné que les expressions entre parenthèses ne sont pas répertoriées comme une instruction d'expression valide, il ne s'agit pas d'une instruction valide selon la spécification. La raison pour laquelle les concepteurs ont choisi de le faire de cette façon est une hypothèse, mais mon pari est que les parenthèses ne font aucun travail utile si la déclaration entière est contenue entre parenthèses:
stmt
et(stmt)
sont exactement les mêmes.la source
OP
ne demande rien sur la conception du langage. Il veut juste savoir pourquoi c'est une erreur. La réponse est: parce que ce n'est pas une déclaration valide .parce que les crochets autour de
i++
créent / définissent une expression .. comme le message d'erreur l'indique .. une expression simple ne peut pas être utilisée comme instruction.pourquoi le langage a été conçu pour être ainsi? pour éviter les bogues, ayant des expressions trompeuses comme instructions, qui ne produisent aucun effet secondaire comme avoir le code
la deuxième ligne n'a aucun effet (mais vous ne l'avez peut-être pas remarqué). Mais au lieu que le compilateur le supprime (car le code n'est pas nécessaire), il vous demande explicitement de le supprimer (vous serez donc au courant de l'erreur) OU de le corriger au cas où vous auriez oublié de taper quelque chose.
modifier :
pour rendre la partie sur les crochets plus claire .. les crochets en c # (en plus d'autres utilisations, comme le cast et l'appel de fonction), sont utilisés pour regrouper des expressions et renvoyer une seule expression (créer les sous-expressions).
à ce niveau de code, seuls les staments sont autorisés.
mais en utilisant le crochet, vous le transformez en expression
et ça
n'est pas valide car le compilateur ne peut pas garantir que l'expression est un effet secondaire (non sans entraîner le problème d'arrêt).
la source
j
j++;
est une déclaration valide, mais en utilisant les crochets, vous diteslet me take this stement and turn it into an expression
.. et les expressions ne sont pas valides à ce stade du code