Menu

Variabili in C#: var, const, readonly, ambito e nomi

Come dichiarare e assegnare le variabili in C#, quando var è una buona idea e quando no, come funziona l'ambito, la differenza tra const, readonly e static readonly, le convenzioni sui nomi e l'errore della variabile non assegnata.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

Una variabile è una posizione di memoria con un nome e un tipo fisso. In C# la dichiari con un tipo e un nome, e facoltativamente le dai un valore nella stessa istruzione. Il tipo poi non cambia più: una variabile int contiene numeri interi per tutto il tempo in cui esiste.

Output:

Priya bought 5 items for 20.25
10

Assegnare un valore del tipo sbagliato è un errore di compilazione: quantity = "five"; fallisce con CS0029 (cannot implicitly convert type 'string' to 'int'). La conversione tra tipi è esplicita; vedi conversione di tipo.

var: lasciare che il compilatore deduca il tipo

var dichiara una variabile locale il cui tipo viene dedotto dal suo inizializzatore. Non è tipizzazione dinamica: il tipo è fissato in fase di compilazione, esattamente come se lo avessi scritto tu.

Output:

String
Int32
Decimal
Double
List`1

var ha tre regole. Funziona solo per le variabili locali (non per campi o parametri). La variabile deve essere inizializzata nella dichiarazione: var x; è l'errore CS0818, "Implicitly-typed variables must be initialized". E l'inizializzatore deve avere un tipo: var nothing = null; non compila, perché null da solo non ha tipo.

Quando usarlo è una questione di stile del team. La linea guida abituale è usare var quando il tipo è ovvio dal lato destro, e scrivere il tipo quando non lo è:

var orders = new List<Order>();         // obvious: var is fine
var reader = new StreamReader(path);    // obvious
decimal discount = CalculateDiscount(); // not obvious: name the type
int count = items.Count();              // makes the intent clear

Una trappola sottile: var total = 0; rende total un int, quindi aggiungergli 2.5 in seguito fallisce, e var price = 10; è un int, non un decimal. Quando il tipo del letterale non è quello che vuoi, scrivi il tipo o aggiungi un suffisso (10m, 0.0).

Ambito

Una variabile locale esiste dalla sua dichiarazione fino alla fine del blocco { } in cui è stata dichiarata. Le variabili dichiarate nell'intestazione di un ciclo o nel corpo di un if non sono visibili dopo.

Output:

high
240

A differenza di C e C++, C# non permette a un blocco interno di dichiarare una variabile locale con lo stesso nome di una del blocco che lo contiene (errore CS0136): il nome deve avere un solo significato in tutto il metodo. Due blocchi fratelli possono riusare un nome, come fanno due cicli for separati che dichiarano ciascuno i.

Assegnazione definita

Le variabili locali non hanno un valore predefinito. Il compilatore segue ogni percorso all'interno del metodo e si rifiuta di compilare se una variabile potrebbe essere letta prima di essere stata assegnata:

int discount;
if (isMember)
{
    discount = 10;
}
Console.WriteLine(discount);
// error CS0165: Use of unassigned local variable 'discount'

Risolvi inizializzandola nella dichiarazione (int discount = 0;) o assegnandola in ogni ramo (aggiungi un else). Campi ed elementi degli array sono diversi: vengono impostati automaticamente al valore predefinito del loro tipo (0, false, null).

const: costanti di compilazione

Una const è un valore fissato in fase di compilazione. Deve essere inizializzata con un'espressione costante (un letterale, un'altra const, o operazioni aritmetiche su di esse), e può essere solo un numero, un char, un bool, una string, un enum o null.

Output:

Price in EUR
120.00 EUR
350

Un campo const è implicitamente static, quindi vi si accede tramite il nome del tipo (Pricing.VatRate), e scrivere static const è un errore. Il compilatore copia il valore in ogni punto che lo usa, ed è per questo che le const non costano nulla a runtime, e anche per questo una const pubblica in una libreria dovrebbe essere un valore che non cambierà mai (come il numero di giorni in una settimana).

readonly e static readonly

Un campo readonly si può assegnare solo nella sua dichiarazione o in un costruttore della sua classe. Dopo la costruzione non può più cambiare. A differenza di const, il suo valore viene calcolato a runtime, può essere di qualsiasi tipo e può essere diverso da un oggetto all'altro.

Output:

ACC-17 opened 2024-05-02
Launch: 2020-01-15
basic, pro

Le ultime righe mostrano il malinteso più comune: readonly protegge il campo, non l'oggetto a cui punta. Plans farà sempre riferimento allo stesso array, ma gli elementi dell'array possono comunque cambiare. Per collezioni davvero immutabili usa ReadOnlyCollection<T> o ImmutableArray<T>.

Riepilogo dei tre:

constreadonlystatic readonly
Valore notoIn fase di compilazioneA runtimeA runtime
Tipi consentitiNumeri, char, bool, string, enum, nullQualsiasiQualsiasi
Impostato inSolo nella dichiarazioneDichiarazione o costruttoreDichiarazione o costruttore statico
Per oggetto o condivisoCondiviso (implicitamente static)Per oggettoCondiviso
Variabili localiSì (const int x = 1;)NoNo

Convenzioni sui nomi

I nomi in C# distinguono maiuscole e minuscole (total e Total sono variabili diverse) e devono iniziare con una lettera o un trattino basso. Le convenzioni di Microsoft, seguite da quasi tutto il codice C#:

  • Variabili locali e parametri: camelCase (orderCount, unitPrice).
  • Costanti, proprietà, metodi, classi e campi pubblici: PascalCase (MaxItems, VatRate).
  • Campi privati: _camelCase con un trattino basso iniziale (_balance), una convenzione diffusa nel codice .NET.
  • I booleani si leggono come domande: isActive, hasDiscount, canRetry.
  • Evita abbreviazioni e prefissi ungheresi (strName, iCount).

Una parola chiave di C# non può essere un nome, a meno che tu non la faccia precedere da @: var @class = "5B"; è lecito, cosa che a volte torna utile per il codice generato o per i nomi dei campi JSON.

Scambio e assegnazione multipla

Da C# 7, le tuple ti permettono di assegnare più variabili in una sola istruzione, il che dà uno scambio in una riga:

Output:

20 10
Lisbon: 545,000

La seconda forma è la decostruzione: dichiara city come string e population come int a partire da una tupla. Approfondisci in tuple.

Domande frequenti

Cos'è var in C#?

var dice al compilatore di dedurre il tipo di una variabile locale dal valore con cui viene inizializzata: var count = 5; dichiara un int. La variabile resta tipizzata staticamente e in seguito non può contenere una stringa. var funziona solo per le variabili locali inizializzate nella stessa istruzione.

Qual è la differenza tra const e readonly in C#?

Una const è una costante di compilazione: il suo valore deve essere noto al momento della compilazione (numeri, stringhe, bool, null), è implicitamente statica, e il valore viene copiato in ogni punto che la usa. Un campo readonly viene impostato una sola volta a runtime, nella sua dichiarazione o in un costruttore, può contenere qualsiasi tipo e può essere diverso per ogni oggetto.

Quando conviene usare static readonly invece di const?

Usa static readonly per un valore condiviso che non può essere una costante di compilazione, come un DateTime, un array o un oggetto, oppure per un valore pubblico che potrebbe cambiare tra una versione e l'altra di una libreria. Dato che i valori const vengono copiati negli assembly chiamanti, cambiare una const pubblica richiede di ricompilare ogni assembly che la usa.

Cosa significa "use of unassigned local variable" in C#?

Errore CS0165: il compilatore ha trovato un percorso in cui una variabile locale viene letta prima che le sia stato assegnato un valore. In C# le variabili locali non hanno un valore predefinito. Inizializza la variabile quando la dichiari, oppure assicurati che ogni ramo di if/switch le assegni un valore prima che venga usata.

Meglio var o i tipi espliciti in C#?

Vanno bene entrambi; i team scelgono uno stile. Una regola comune è usare var quando il tipo è ovvio dal lato destro (var list = new List<string>();) e scrivere il tipo quando non lo è (decimal total = GetTotal();). Il codice del runtime di .NET segue più o meno questa regola.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA