Dlaczego C # pozwalają bloki kodu bez uprzedniego oświadczenia (np if
, else
, for
, while
)?
void Main()
{
{ // any sense in this?
Console.Write("foo");
}
}
Dlaczego C # pozwalają bloki kodu bez uprzedniego oświadczenia (np if
, else
, for
, while
)?
void Main()
{
{ // any sense in this?
Console.Write("foo");
}
}
Odpowiedzi:
W podanym przez ciebie kontekście nie ma to znaczenia. Zapisanie stałego ciągu do konsoli będzie działać w ten sam sposób w każdym miejscu przepływu programu. 1
Zamiast tego zazwyczaj używa się ich do ograniczenia zakresu niektórych zmiennych lokalnych. Jest to bardziej szczegółowo omówione tutaj i tutaj . Spójrz na odpowiedź João Angelo i odpowiedzi Chris Wallisa dla krótkich przykładów. Uważam, że to samo odnosi się również do niektórych innych języków ze składnią w stylu C, ale nie żeby były one odpowiednie dla tego pytania.
1 Chyba że zdecydujesz się być zabawny i stworzyć własną Console
klasę za pomocą Write()
metody, która robi coś zupełnie nieoczekiwanego.
out
parametru do napisanej implementacji interfejsu w innym języku i ta implementacja czyta zmienną przed jej zapisaniem.
Plik { ... }
Ma co najmniej efekt uboczny wprowadzenie nowego zakresu zmiennych lokalnych.
Zwykle używam ich w switch
instrukcjach, aby zapewnić inny zakres dla każdego przypadku i w ten sposób pozwalając mi zdefiniować zmienną lokalną o tej samej nazwie w najbliższym możliwym miejscu ich użycia, a także zaznaczyć, że są one ważne tylko na poziomie przypadku.
{}
jak zachować te złote odznaki ... :)
Jest to nie tyle funkcja C #, ile logiczny efekt uboczny wielu języków składni C, które używają nawiasów klamrowych do definiowania zakresu .
W naszym przykładzie nawiasy klamrowe nie mają żadnego efektu, ale w poniższym kodzie definiują zakres, a tym samym widoczność zmiennej:
Jest to dozwolone, ponieważ i wykracza poza zakres w pierwszym bloku i jest ponownie definiowane w następnym:
{
{
int i = 0;
}
{
int i = 0;
}
}
Jest to niedozwolone, ponieważ i wypadło poza zakres i nie jest już widoczne w zakresie zewnętrznym:
{
{
int i = 0;
}
i = 1;
}
I tak dalej i tak dalej.
{}
znane jako nawiasy?
One of two marks of the form [ ] or ( ), and in mathematical use also {}, used for enclosing a word or number of words, a portion of a mathematical formula, or the like, so as to separate it from the context;
W każdym razie nie są to nawiasy, ale „nawias klamrowy” wydaje się OK.
Uważam za {}
stwierdzenie, które może zawierać kilka stwierdzeń.
Rozważmy instrukcję if, która istnieje z wyrażenia logicznego, po którym następuje jedna instrukcja. To zadziała:
if (true) Console.Write("FooBar");
To również zadziała:
if (true)
{
Console.Write("Foo");
Console.Write("Bar");
}
Jeśli się nie mylę, nazywa się to instrukcją blokową.
Ponieważ {}
może zawierać inne stwierdzenia, może również zawierać inne {}
. Zakres zmiennej jest określony przez jej rodzica {}
(instrukcję blokową).
Chodzi mi o to, że {}
jest to tylko stwierdzenie, więc nie wymaga czy lub czegokolwiek ...
Ogólna zasada w językach C-składni brzmi: „wszystko pomiędzy { }
powinno być traktowane jako pojedyncza instrukcja i może dotyczyć wszędzie tam, gdzie mogłoby to zrobić”:
if
.for
, while
lub do
.Pod każdym względem gramatyka języka zawierała to:
<statement> :== <definition of valid statement> | "{" <statement-list> "}"
<statement-list> :== <statement> | <statement-list> <statement>
Oznacza to, że „instrukcja może składać się z (różnych elementów) lub nawiasu otwierającego, po którym następuje lista instrukcji (która może zawierać jedno lub więcej instrukcji), po której następuje nawias zamykający”. IE "a{ }
blok może zastąpić dowolną instrukcję w dowolnym miejscu”. W tym w środku kodu.
Niedopuszczenie do umieszczenia { }
bloku w dowolnym miejscu, w którym mogłoby dojść do pojedynczej instrukcji, w rzeczywistości uczyniłoby definicję języka bardziej złożoną .
Ponieważ C ++ (i java) zezwalały na bloki kodu bez poprzedzającej instrukcji.
C ++ pozwolił im na to, ponieważ zrobił to C.
Można powiedzieć, że wszystko sprowadza się do tego, że zwyciężył projekt w amerykańskim języku programowania (oparty na języku C), a nie w europejskim języku programowania (w oparciu o Modula-2 ).
(Instrukcje sterujące działają na pojedynczą instrukcję, instrukcje mogą być grupami, aby tworzyć nowe instrukcje)
// if (a == b)
// if (a != b)
{
// do something
}
Zapytałeś „dlaczego” C # zezwala na bloki kodu bez poprzedzających instrukcji. Pytanie „dlaczego” można również interpretować jako „jakie byłyby możliwe korzyści z tego konstruktu?”
Osobiście używam bloków kodu bez instrukcji w C #, gdzie czytelność jest znacznie poprawiona dla innych programistów, pamiętając jednocześnie, że blok kodu ogranicza zakres zmiennych lokalnych. Weźmy na przykład pod uwagę następujący fragment kodu, który jest znacznie łatwiejszy do odczytania dzięki dodatkowym blokom kodu:
OrgUnit world = new OrgUnit() { Name = "World" };
{
OrgUnit europe = new OrgUnit() { Name = "Europe" };
world.SubUnits.Add(europe);
{
OrgUnit germany = new OrgUnit() { Name = "Germany" };
europe.SubUnits.Add(germany);
//...etc.
}
}
//...commit structure to DB here
Zdaję sobie sprawę, że można to rozwiązać bardziej elegancko, stosując metody dla każdego poziomu konstrukcji. Ale z drugiej strony pamiętaj, że takie rzeczy, jak przykładowe serwery danych, zwykle muszą być szybkie.
Tak więc, mimo że powyższy kod jest wykonywany liniowo, struktura kodu reprezentuje strukturę obiektów w „świecie rzeczywistym”, ułatwiając w ten sposób innym programistom zrozumienie, utrzymanie i rozszerzenie.