Poniższy kod jest nieprawidłowy (zobacz go na ideone ):
public class Test
{
public static void Main()
{
int j = 5;
(j++); // if we remove the "(" and ")" then this compiles fine.
}
}
błąd CS0201: Tylko przypisanie, wywołanie, inkrementacja, dekrementacja, await i nowe wyrażenia obiektu mogą być używane jako instrukcja
- Dlaczego kod kompiluje się, gdy usuwamy nawiasy?
- Dlaczego nie kompiluje się z nawiasami?
- Dlaczego C # został zaprojektowany w ten sposób?
c#
syntax
expression
language-design
parentheses
user10607
źródło
źródło
Odpowiedzi:
Zrobię co w mojej mocy.
Jak zauważyły inne odpowiedzi, kompilator wykrywa, że wyrażenie jest używane jako instrukcja . W wielu językach - C, JavaScript i wielu innych - użycie wyrażenia jako instrukcji jest całkowicie legalne.
2 + 2;
jest legalne w tych językach, mimo że jest to stwierdzenie, które nie ma żadnego skutku. Niektóre wyrażenia są przydatne tylko ze względu na ich wartości, niektóre wyrażenia są przydatne tylko ze względu na ich skutki uboczne (takie jak wywołanie metody zwracającej void), a niektóre wyrażenia niestety są przydatne w obu przypadkach. (Podobnie jak przyrost.)Chodzi o to, że stwierdzenia, które składają się tylko z wyrażeń, są prawie na pewno błędami, chyba że te wyrażenia są zwykle uważane za bardziej przydatne ze względu na ich skutki uboczne niż ich wartości . Projektanci języka C # chcieli znaleźć kompromis, dopuszczając wyrażenia, które były ogólnie uważane za efekt uboczny, jednocześnie odrzucając te, które są również zwykle uważane za przydatne dla ich wartości. Zbiór wyrażeń, które zidentyfikowali w C # 1.0, to przyrosty, ubytki, wywołania metod, przypisania i nieco kontrowersyjne wywołania konstruktorów.
POZA STRONĄ: Zwykle uważa się, że konstrukcja obiektu jest używana ze względu na wartość, którą wytwarza, a nie jako efekt uboczny konstrukcji; moim zdaniem przyzwolenie
new Foo();
jest trochę błędem. W szczególności widziałem ten wzorzec w rzeczywistym kodzie, który spowodował usterkę bezpieczeństwa:Zaskakująco trudno jest wykryć tę wadę, jeśli kod jest skomplikowany.
Dlatego kompilator wykrywa wszystkie instrukcje zawierające wyrażenia, których nie ma na tej liście. W szczególności wyrażenia w nawiasach są identyfikowane właśnie jako takie - wyrażenia w nawiasach. Nie ma ich na liście „dozwolonych jako wyrażenia instrukcji”, więc są niedozwolone.
Wszystko to służy zasadzie projektowania języka C #. Jeśli wpisałeś
(x++);
, prawdopodobnie zrobiłeś coś nie tak . To prawdopodobnie literówkaM(x++);
lub po prostu coś. Pamiętaj, nastawienie zespołu kompilatora C # nie brzmi: „ czy możemy wymyślić jakiś sposób, aby to zadziałało? ”. Postawa zespołu kompilatora C # brzmi: „ jeśli wiarygodny kod wygląda na prawdopodobny błąd, poinformujmy o tym programistę ”. Deweloperzy C # lubią to podejście.Teraz wszystko, co powiedział, jest rzeczywiście kilka dziwnych przypadków, w których specyfikacja C # ma sugerować lub państwowe wprost, że nawiasy są niedozwolone, ale kompilator C # pozwala je tak czy inaczej. W prawie wszystkich tych przypadkach niewielka rozbieżność między określonym zachowaniem a dozwolonym zachowaniem jest całkowicie nieszkodliwa, więc twórcy kompilatorów nigdy nie naprawili tych małych błędów. Możesz przeczytać o nich tutaj:
Czy istnieje różnica między return myVar a return (myVar)?
źródło
... ? ... : ...
, w których poprawką jest użycieif
/else
zamiast.)contineu;
.try { new Foo(null); } catch (ArgumentNullException)...
ale oczywiście te sytuacje z definicji nie są kodem produkcyjnym. Wydaje się rozsądne, że taki kod można napisać w celu przypisania do zmiennej fikcyjnej.W specyfikacji języka C #
Umieszczenie nawiasów wokół instrukcji tworzy nowe tak zwane wyrażenie w nawiasach. Ze specyfikacji:
Ponieważ wyrażenia w nawiasach nie są wymienione jako prawidłowe wyrażenie wyrażenia, zgodnie ze specyfikacją nie są one prawidłowe. Nikt nie wie, dlaczego projektanci zdecydowali się to zrobić w ten sposób, ale zakładam, że nawiasy nie działają, jeśli całe stwierdzenie jest zawarte w nawiasach:
stmt
i(stmt)
są dokładnie takie same.źródło
OP
pyta o projekt języka. Chce tylko wiedzieć, dlaczego to błąd. Odpowiedź brzmi: ponieważ nie jest to prawidłowe stwierdzenie .ponieważ nawiasy wokół
i++
znaku tworzą / definiują wyrażenie… jak mówi komunikat o błędzie… proste wyrażenie nie może być użyte jako instrukcja.dlaczego język został tak zaprojektowany? aby uniknąć błędów, wprowadzających w błąd wyrażeń jako instrukcji, które nie wywołują skutków ubocznych, takich jak posiadanie kodu
druga linia nie ma żadnego efektu (ale być może nie zauważyłeś). Ale zamiast usuwać go przez kompilator (ponieważ kod nie jest potrzebny). Wyraźnie prosi o usunięcie go (więc będziesz świadomy błędu) LUB napraw to, jeśli zapomniałeś czegoś wpisać.
edytuj :
aby część dotycząca nawiasów była bardziej przejrzysta ... nawiasy w języku c # (oprócz innych zastosowań, takich jak rzutowanie i wywołanie funkcji), służą do grupowania wyrażeń i zwracania pojedynczego wyrażenia (tworzenia wyrażeń podrzędnych).
na tym poziomie kodu dozwolone są tylko stamenty ... tak
ale używając nawiasu zamieniasz go w wyrażenie
i to
jest niepoprawne, ponieważ kompilator nie może zapewnić, że wyrażenie jest efektem ubocznym. (nie bez wystąpienia problemu zatrzymania).
źródło
j
zmiennej, prawda?j++;
jest prawidłową instrukcją, ale używając nawiasów, o których mówiszlet me take this stement and turn it into an expression
... a wyrażenia nie są poprawne w tym miejscu w kodzie