O código a seguir está errado (veja no ideone ):
public class Test
{
public static void Main()
{
int j = 5;
(j++); // if we remove the "(" and ")" then this compiles fine.
}
}
erro CS0201: Apenas designação, chamada, incremento, decremento, espera e novas expressões de objeto podem ser usadas como uma instrução
- Por que o código é compilado quando removemos os parênteses?
- Por que não compila com parênteses?
- Por que o C # foi projetado dessa maneira?
c#
syntax
expression
language-design
parentheses
user10607
fonte
fonte
Respostas:
Eu farei o meu melhor.
Como outras respostas observaram, o que está acontecendo aqui é que o compilador está detectando que uma expressão está sendo usada como uma declaração . Em muitos idiomas - C, JavaScript e muitos outros - é perfeitamente legal usar uma expressão como uma declaração.
2 + 2;
é legal nesses idiomas, mesmo que essa seja uma declaração que não tem efeito. Algumas expressões são úteis apenas para seus valores, algumas expressões são úteis apenas para seus efeitos colaterais (como uma chamada para um método de retorno nulo) e algumas expressões, infelizmente, são úteis para ambos. (Como incremento.)A questão é: declarações que consistem apenas em expressões são quase certamente erros, a menos que essas expressões sejam consideradas mais úteis para seus efeitos colaterais do que seus valores . Os designers de C # desejavam encontrar um meio termo, permitindo expressões que geralmente eram consideradas como efeito colateral, enquanto não permitiam aquelas que também são geralmente consideradas úteis para seus valores. O conjunto de expressões que eles identificaram no C # 1.0 foram incrementos, decréscimos, chamadas de método, atribuições e, de certa forma controversa, invocações de construtores.
À parte: Normalmente, considera-se uma construção de objeto como sendo usada pelo valor que produz, não pelo efeito colateral da construção; na minha opinião, permitir
new Foo();
é um pouco incorreto. Em particular, eu vi esse padrão no código do mundo real que causou um defeito de segurança:Pode ser surpreendentemente difícil detectar esse defeito se o código for complicado.
O compilador, portanto, trabalha para detectar todas as instruções que consistem em expressões que não estão nessa lista. Em particular, expressões entre parênteses são identificadas como exatamente isso - expressões entre parênteses. Eles não estão na lista de "permitido como expressões de instrução", portanto, não são permitidos.
Tudo isso está em serviço de um princípio de design da linguagem C #. Se você digitou
(x++);
, provavelmente estava fazendo algo errado . Este é provavelmente um erro de digitaçãoM(x++);
ou algo justo. Lembre-se, a atitude da equipe do compilador C # não é " podemos descobrir uma maneira de fazer isso funcionar? " A atitude da equipe do compilador C # é " se um código plausível parecer um provável erro, vamos informar o desenvolvedor ". Desenvolvedores de C # gostam dessa atitude.Agora, tudo o que disse, realmente existem alguns casos estranhos onde o # especificação C não implicam ou estaduais abertamente que parênteses são permitidos, mas o compilador C # permite que eles de qualquer maneira. Em quase todos esses casos, a menor discrepância entre o comportamento especificado e o permitido é totalmente inofensiva, portanto, os escritores do compilador nunca corrigiram esses pequenos bugs. Você pode ler sobre aqueles aqui:
Existe uma diferença entre return myVar vs. return (myVar)?
fonte
... ? ... : ...
, em que a solução é para usarif
/else
em vez disso.)contineu;
.try { new Foo(null); } catch (ArgumentNullException)...
mas obviamente essas situações são, por definição, não código de produção. Parece razoável que esse código possa ser escrito para atribuir a uma variável dummy.Na especificação da linguagem C #
Colocar parênteses em torno de uma instrução cria uma nova expressão chamada parênteses. A partir da especificação:
Como expressões entre parênteses não são listadas como uma declaração de expressão válida, não é uma declaração válida de acordo com a especificação. Por que os designers optaram por fazê-lo dessa maneira é uma incógnita, mas minha aposta é que parênteses não funcionam de maneira útil se toda a declaração estiver entre parênteses:
stmt
e(stmt)
são exatamente os mesmos.fonte
OP
nada está perguntando sobre o design da linguagem. Ele só quer saber por que isso é um erro. A resposta é: porque não é uma afirmação válida .porque os colchetes ao redor do
i++
estão criando / definindo uma expressão .. como a mensagem de erro diz .. uma expressão simples não pode ser usada como uma declaração.por que a linguagem foi projetada para ser assim? para evitar bugs, tendo expressões enganosas como instruções, que não produzem efeitos colaterais como ter o código
a segunda linha não tem efeito (mas você pode não ter percebido). Mas, em vez de o compilador removê-lo (porque o código não é necessário), ele solicita explicitamente que você o remova (para que você fique ciente ou com o erro) OU corrija-o caso se esqueça de digitar algo.
editar :
para tornar a parte sobre bracked mais clara .. colchetes em c # (além de outros usos, como conversão de funções e chamada de função), são usados para agrupar expressões e retornar uma única expressão (marca das subexpressões).
nesse nível de código, apenas staments são permitidos.
mas usando o colchete você o transforma como expressão
e isto
não é válido porque o compilador não pode garantir que a expressão seja efeito colateral. (não sem incorrer no problema de parada) ..
fonte
j
variável, certo?j++;
é uma declaração válida, mas usando os suportes que você está dizendolet me take this stement and turn it into an expression
.. e expresions não são válidos nesse momento no código