Perché C # permette blocchi di codice senza una dichiarazione precedente (ad esempio if
, else
, for
, while
)?
void Main()
{
{ // any sense in this?
Console.Write("foo");
}
}
Perché C # permette blocchi di codice senza una dichiarazione precedente (ad esempio if
, else
, for
, while
)?
void Main()
{
{ // any sense in this?
Console.Write("foo");
}
}
Risposte:
Nel contesto che dai, non c'è significato. Scrivere una stringa costante sulla console funzionerà allo stesso modo ovunque nel flusso del programma. 1
Invece, in genere li usi per limitare l'ambito di alcune variabili locali. Questo è ulteriormente elaborato qui e qui . Guardate la risposta di João Angelo e la risposta di Chris Wallis per gli esempi brevi. Credo che lo stesso si applichi anche ad altri linguaggi con sintassi in stile C, non che siano rilevanti per questa domanda.
1 A meno che, naturalmente, non decidi di provare a essere divertente e di creare la tua Console
lezione, con un Write()
metodo che fa qualcosa di completamente inaspettato.
out
parametro a un'implementazione dell'interfaccia scritta in un'altra lingua e tale implementazione legge la variabile prima di scriverla.
La { ... }
presenta almeno l'effetto collaterale di introdurre un nuovo ambito per le variabili locali.
Tendo a usarli nelle switch
istruzioni per fornire un ambito diverso per ogni caso e in questo modo mi consente di definire la variabile locale con lo stesso nome nella posizione più vicina possibile del loro utilizzo e per denotare anche che sono valide solo a livello di caso.
{}
per mantenere quei badge d'oro in arrivo ... :)
Non è tanto una funzionalità di C # quanto un effetto collaterale logico di molti linguaggi di sintassi C che utilizzano le parentesi graffe per definire l'ambito .
Nel tuo esempio le parentesi graffe non hanno alcun effetto, ma nel codice seguente definiscono l'ambito, e quindi la visibilità, di una variabile:
Ciò è consentito poiché esco dall'ambito nel primo blocco e viene definito di nuovo nel successivo:
{
{
int i = 0;
}
{
int i = 0;
}
}
Ciò non è consentito in quanto i è uscito dall'ambito e non è più visibile nell'ambito esterno:
{
{
int i = 0;
}
i = 1;
}
E così via.
{}
conosciuti come parentesi?
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;
In ogni caso non sono parentesi, ma "parentesi graffa" sembra OK.
Considero {}
un'affermazione che può contenere diverse affermazioni.
Si consideri un if che esiste fuori di un'espressione booleana seguita da una dichiarazione. Questo funzionerebbe:
if (true) Console.Write("FooBar");
Funzionerebbe anche:
if (true)
{
Console.Write("Foo");
Console.Write("Bar");
}
Se non sbaglio, questa viene chiamata istruzione di blocco.
Poiché {}
può contenere altre affermazioni, ne può contenere anche altre {}
. L'ambito di una variabile è definito dal suo genitore {}
(istruzione block).
Il punto che sto cercando di sottolineare è che {}
è solo un'affermazione, quindi non richiede un se o altro ...
La regola generale nei linguaggi con sintassi C è "qualsiasi cosa tra { }
dovrebbe essere trattata come una singola istruzione e può andare ovunque una singola istruzione potrebbe":
if
.for
, while
o do
.A tutti gli effetti, è perché la grammatica della lingua includeva questo:
<statement> :== <definition of valid statement> | "{" <statement-list> "}"
<statement-list> :== <statement> | <statement-list> <statement>
Cioè, "un'affermazione può essere composta da (varie cose) o da una parentesi graffa di apertura, seguita da un elenco di istruzioni (che può includere una o più affermazioni), seguita da una parentesi graffa chiusa". IE "un { }
blocco può sostituire qualsiasi istruzione, ovunque". Compreso nel mezzo del codice.
Non consentire un { }
blocco ovunque possa andare una singola istruzione avrebbe effettivamente reso la definizione del linguaggio più complessa .
Perché C ++ (e java) consentivano blocchi di codice senza un'istruzione precedente.
C ++ li ha consentiti perché C lo ha fatto.
Si potrebbe dire che tutto si riduce al fatto che il design del linguaggio di programma USA (basato su C) ha vinto piuttosto che il design del linguaggio di programma europeo ( basato su Modula-2 ).
(Le istruzioni di controllo agiscono su una singola istruzione, le istruzioni possono essere gruppi per creare nuove istruzioni)
// if (a == b)
// if (a != b)
{
// do something
}
Hai chiesto "perché" C # consente blocchi di codice senza istruzioni precedenti. La domanda "perché" potrebbe anche essere interpretata come "quali sarebbero i possibili vantaggi di questo costrutto?"
Personalmente, utilizzo blocchi di codice senza istruzioni in C # in cui la leggibilità è notevolmente migliorata per altri sviluppatori, tenendo presente che il blocco di codice limita l'ambito delle variabili locali. Ad esempio, considera il seguente frammento di codice, che è molto più facile da leggere grazie ai blocchi di codice aggiuntivi:
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
Sono consapevole che questo potrebbe essere risolto in modo più elegante utilizzando metodi per ogni livello di struttura. Ma poi di nuovo, tieni presente che cose come i seeders di dati di esempio di solito devono essere veloci.
Quindi, anche se il codice sopra viene eseguito linearmente, la struttura del codice rappresenta la struttura "del mondo reale" degli oggetti, rendendo così più facile per gli altri sviluppatori la comprensione, la manutenzione e l'estensione.