Почему было утверждение (j ++); запрещено?

Следующий код неверен (см. на ideone):

public class Test
{
    public static void Main()
    {
        int j = 5;
        (j++);      // if we remove the "(" and ")" then this compiles fine.
    }
}

ошибка CS0201: только назначение, вызов, приращение, декремент, ожидание и новые выражения объектов могут использоваться как оператор

  • Почему компиляция кода при удалении круглых скобок?
  • Почему он не компилируется с круглыми скобками?
  • Почему С# был разработан таким образом?

Ответ 1

Глубокое понимание было оценено.

Я сделаю все возможное.

Как отмечают другие ответы, здесь происходит компилятор, обнаруживающий, что выражение используется как оператор. На многих языках - C, JavaScript и многих других - вполне законно использовать выражение как инструкцию. 2 + 2; является законным на этих языках, хотя это утверждение не имеет никакого эффекта. Некоторые выражения полезны только для их значений, некоторые выражения полезны только для их побочных эффектов (например, для вызова метода возврата пустоты), а некоторые выражения, к сожалению, полезны для обоих. (Как приращение.)

Точка: заявления, которые состоят только из выражений, почти наверняка являются ошибками, если эти выражения обычно не считаются более полезными для их побочных эффектов, чем их значения. Дизайнеры С# хотели найти среднюю позицию, разрешив выражения, которые обычно считались побочными, и не разрешающие те, которые также обычно считаются полезными для их ценностей. Набор выражений, которые они идентифицировали в С# 1.0, - это приращения, декременты, вызовы методов, назначения и несколько противоречивые вызовы конструктора.


ASIDE: Обычно считается, что конструкция объекта используется для ценности, которую она производит, а не для побочного эффекта конструкции; по-моему, разрешая new Foo(); немного нехорошо. В частности, я видел эту модель в коде реального мира, которая вызвала дефект безопасности:

catch(FooException ex) { new BarException(ex); } 

Удивительно сложно определить этот дефект, если код сложный.


Таким образом, компилятор работает для обнаружения всех операторов, которые состоят из выражений, которые не входят в этот список. В частности, выраженные в скобках выражения называются именно такими - выраженными в скобках выражениями. Они не входят в список "разрешенных выражений оператора", поэтому они запрещены.

Все это работает с принципом дизайна языка С#. Если вы набрали (x++);, вы, вероятно, сделали что-то не так.. Вероятно, это опечатка для M(x++); или какой-то просто вещи. Помните, что отношение команды компилятора С# не "может мы каким-то образом решить эту задачу?" Отношение команды компилятора С# "если правдоподобный код выглядит как вероятная ошибка, сообщите об этом разработчику". С# разработчикам нравится это отношение.

Теперь, все, что было сказано, на самом деле есть несколько нечетных случаев, когда спецификация С# подразумевает или утверждает, что скобки не разрешены, но компилятор С# позволяет им в любом случае. Почти во всех этих случаях незначительное несоответствие между указанным поведением и допустимым поведением является абсолютно безобидным, поэтому авторы компилятора никогда не исправляли эти небольшие ошибки. Вы можете прочитать о них здесь:

Есть ли разница между return myVar и return (myVar)?

Ответ 2

В Спецификация языка С#

Операторы выражения используются для оценки выражений. Выражения, которые могут использоваться в качестве операторов, включают в себя вызовы методов, распределения объектов с использованием нового оператора, назначения с использованием = и составных операторов присваивания, операции увеличения и уменьшения с использованием операторов ++ и - и ожидания.

Помещение круглых скобок вокруг оператора создает новое так называемое выражение в скобках. Из спецификации:

Выражение в скобках состоит из выражения, заключенного в круглые скобки.... Выражение в скобках оценивается путем вычисления выражения в круглых скобках. Если выражение в круглых скобках обозначает пространство имен или тип, возникает ошибка времени компиляции. В противном случае результат выражения в скобках является результатом оценки содержащегося выражения.

Так как заключенные в скобки выражения не указаны как допустимый оператор выражения, это не является допустимым утверждением в соответствии со спецификацией. Почему дизайнеры решили сделать это таким образом, кто-то догадывается, но моя ставка заключается в том, что в скобках нет полезной работы, если весь оператор содержится в круглых скобках: stmt и (stmt) точно такие же.

Ответ 3

because, когда скобки вокруг i++ создают/определяют выражение.. как говорится в сообщении об ошибке.. простое выражение can not используется как оператор.

почему язык был разработан таким образом? для предотвращения ошибок, вводящих в заблуждение выражений в качестве операторов, которые не создают побочных эффектов, например, имеют код

int j = 5;
j+1; 

вторая строка не имеет эффекта (но вы, возможно, не заметили). Но вместо того, чтобы компилятор удалял его (потому что код не нужен).it явно просит вас удалить его (так что вам будет известно или ошибка) ИЛИ исправить его, если вы забыли что-то ввести.

изменить

чтобы сделать часть о скобках более четкой. скобки в С# (помимо других применений, таких как вызов приведения и функции), используются для группировки выражений и возврата одного выражения (make из подвыражений).

на этом уровне кода разрешены только строки. так что

j++; is a valid statement because it produces side effects

но с помощью скобки вы превращаете его в выражение

myTempExpression = (j++)

и этот

myTempExpression;

недействителен, потому что компилятор не может утверждать, что выражение как побочный эффект (не лишившись проблемы с остановкой).