El siguiente código es incorrecto (verlo en ideone ):
public class Test
{
public static void Main()
{
int j = 5;
(j++); // if we remove the "(" and ")" then this compiles fine.
}
}
error CS0201: solo las asignaciones, llamadas, incrementos, decrementos, esperas y nuevas expresiones de objetos se pueden usar como una declaración
- ¿Por qué se compila el código cuando eliminamos los paréntesis?
- ¿Por qué no se compila con los paréntesis?
- ¿Por qué se diseñó C # de esa manera?
c#
syntax
expression
language-design
parentheses
usuario10607
fuente
fuente
Respuestas:
Haré lo mejor que pueda.
Como han señalado otras respuestas, lo que está sucediendo aquí es que el compilador está detectando que una expresión se está utilizando como una declaración . En muchos lenguajes, C, JavaScript y muchos otros, es perfectamente legal usar una expresión como una declaración.
2 + 2;
es legal en estos idiomas, a pesar de que esta es una declaración que no tiene ningún efecto. Algunas expresiones son útiles solo por sus valores, algunas expresiones son útiles solo por sus efectos secundarios (como una llamada a un método de retorno nulo) y algunas expresiones, desafortunadamente, son útiles para ambos. (Como incremento).El punto es: las declaraciones que consisten solo en expresiones son casi con certeza errores a menos que esas expresiones se consideren más útiles para sus efectos secundarios que sus valores . Los diseñadores de C # deseaban encontrar un punto medio, permitiendo expresiones que generalmente se consideraban como efectos secundarios, mientras que no permitían aquellas que también se consideran útiles para sus valores. El conjunto de expresiones que identificaron en C # 1.0 fueron incrementos, decrementos, llamadas a métodos, asignaciones y, de forma algo controvertida, invocaciones de constructores.
A UN LADO: Uno normalmente piensa que la construcción de un objeto se usa por el valor que produce, no por el efecto secundario de la construcción; en mi opinión, permitir
new Foo();
es un poco un error. En particular, he visto este patrón en el código del mundo real que causó un defecto de seguridad:Puede ser sorprendentemente difícil detectar este defecto si el código es complicado.
Por lo tanto, el compilador funciona para detectar todas las declaraciones que consisten en expresiones que no están en esa lista. En particular, las expresiones entre paréntesis se identifican solo como eso: expresiones entre paréntesis. No están en la lista de "permitidas como expresiones de declaración", por lo que no están permitidas.
Todo esto está al servicio de un principio de diseño del lenguaje C #. Si escribiste
(x++);
, probablemente estabas haciendo algo mal . Esto es probablemente un error tipográficoM(x++);
o algo justo. Recuerde, la actitud del equipo compilador de C # no es " ¿podemos encontrar alguna forma de hacer que esto funcione? " La actitud del equipo compilador de C # es " si el código plausible parece un posible error, informemos al desarrollador ". A los desarrolladores de C # les gusta esa actitud.Ahora, todo lo que dijo, en realidad hay unos pocos casos raros en que la especificación C # no implica ni del estado de plano que los paréntesis no están permitidos, pero el compilador de C # les permite de todos modos. En casi todos esos casos, la discrepancia menor entre el comportamiento especificado y el comportamiento permitido es completamente inofensiva, por lo que los escritores del compilador nunca han solucionado estos pequeños errores. Puedes leer sobre eso aquí:
¿Hay alguna diferencia entre return myVar y return (myVar)?
fuente
... ? ... : ...
, dónde se debe usar la soluciónif
/ en suelse
lugar.)contineu;
.try { new Foo(null); } catch (ArgumentNullException)...
pero obviamente estas situaciones son, por definición, no un código de producción. Parece razonable que dicho código se pueda escribir para asignar a una variable ficticia.En la especificación del lenguaje C #
Poner paréntesis alrededor de una declaración crea una nueva llamada expresión entre paréntesis. De la especificación:
Dado que las expresiones entre paréntesis no se enumeran como una declaración de expresión válida, no es una declaración válida según la especificación. Nadie sabe con certeza por qué los diseñadores decidieron hacerlo de esta manera, pero mi apuesta es porque los paréntesis no son útiles si la declaración completa está entre paréntesis:
stmt
y(stmt)
son exactamente lo mismo.fuente
OP
no pregunta nada sobre el diseño del lenguaje. Solo quiere saber por qué esto es un error. La respuesta es: porque no es una declaración válida .porque los corchetes alrededor del
i++
están creando / definiendo una expresión ... como dice el mensaje de error ... una expresión simple no puede usarse como una declaración.¿Por qué el lenguaje fue diseñado para ser así? para evitar errores, que tienen expresiones engañosas como declaraciones, que no producen ningún efecto secundario como tener el código
la segunda línea no tiene efecto (pero puede que no lo hayas notado). Pero en lugar de que el compilador lo elimine (porque el código no es necesario). Explícitamente le pide que lo elimine (para que sepa el error) O lo arregle en caso de que haya olvidado escribir algo.
editar :
para aclarar más la parte sobre el frenado ... los corchetes en c # (además de otros usos, como la conversión y la llamada a funciones), se usan para agrupar expresiones y devolver una sola expresión (marca de las subexpresiones).
en ese nivel de código solo se permiten declaraciones ...
pero al usar el freno lo estás convirtiendo en una expresión
y esto
no es válido porque el compilador no puede asegurar que la expresión sea un efecto secundario (no sin incurrir en el problema de detención).
fuente
j
variable ¿verdad?j++;
es una declaración válida, pero al usar los corchetes estás diciendolet me take this stement and turn it into an expression
... y las expresiones no son válidas en ese punto del código