Operatori e strutture di controllo in C#
Un programma diventa davvero utile quando è in grado di prendere decisioni e di ripetere operazioni. Gli operatori permettono di combinare e confrontare i valori, mentre le strutture di controllo determinano il flusso di esecuzione, ovvero l'ordine in cui le istruzioni vengono eseguite. In questo articolo esaminiamo gli operatori principali di C# e le costruzioni che governano condizioni e cicli, elementi che ritroveremo in ogni programma.
Operatori aritmetici e di assegnazione
Gli operatori aritmetici eseguono i calcoli fondamentali. Oltre alle quattro operazioni classiche, C# fornisce l'operatore modulo, che restituisce il resto di una divisione, molto utile per verificare la parità o per lavorare con cicli periodici.
int a = 10;
int b = 3;
int sum = a + b; // 13
int difference = a - b; // 7
int product = a * b; // 30
int quotient = a / b; // 3 (divisione intera)
int remainder = a % b; // 1 (resto della divisione)
Gli operatori di assegnazione composta abbreviano le operazioni che modificano una variabile in base al suo valore corrente, mentre gli operatori di incremento e decremento aumentano o diminuiscono di uno.
int counter = 5;
counter += 3; // equivale a counter = counter + 3, ora vale 8
counter -= 2; // ora vale 6
counter++; // incremento, ora vale 7
counter--; // decremento, ora vale 6
Operatori relazionali e logici
Gli operatori relazionali confrontano due valori e producono un risultato booleano. Gli operatori logici combinano più condizioni booleane, permettendo di costruire espressioni complesse.
int age = 25;
bool isAdult = age >= 18; // true
bool isTeenager = age >= 13 && age <= 19; // false: entrambe devono essere vere
bool isSpecialAge = age == 18 || age == 21; // false: basta una vera
Gli operatori logici && e || sono a valutazione "cortocircuitata": se il risultato è già determinato dal primo operando, il secondo non viene valutato. Questo comportamento è spesso sfruttato per evitare valutazioni non necessarie o potenzialmente problematiche.
Operatori per i valori nulli
C# offre operatori pensati specificamente per gestire i valori nulli in modo conciso. L'operatore null-coalescing ?? fornisce un valore alternativo quando l'espressione a sinistra è nulla, mentre l'operatore di accesso condizionale ?. evita di sollevare un'eccezione quando si accede a un membro di un riferimento potenzialmente nullo.
string? input = null;
// Se input e null, si usa il valore predefinito
string result = input ?? "valore predefinito";
// L'accesso condizionale restituisce null invece di sollevare un'eccezione
int? length = input?.Length;
L'istruzione if
L'istruzione if è la struttura decisionale più elementare: esegue un blocco di codice solo se una condizione è vera. Può essere estesa con else per gestire il caso contrario e con else if per valutare condizioni in sequenza.
int score = 75;
if (score >= 90)
{
Console.WriteLine("Ottimo");
}
else if (score >= 60)
{
Console.WriteLine("Sufficiente");
}
else
{
Console.WriteLine("Insufficiente");
}
Per condizioni semplici che assegnano uno di due valori esiste l'operatore ternario, una forma compatta di scelta binaria che si legge come "condizione, valore se vera, valore se falsa":
string label = score >= 60 ? "Promosso" : "Bocciato";
Lo switch
Quando si deve confrontare una stessa variabile con molti valori possibili, la catena di if diventa verbosa. L'istruzione switch offre un'alternativa più leggibile. Ogni ramo case gestisce un valore, e il ramo default intercetta tutti i casi non previsti.
int day = 3;
switch (day)
{
case 1:
Console.WriteLine("Lunedi");
break;
case 6:
case 7:
Console.WriteLine("Weekend");
break;
default:
Console.WriteLine("Giorno feriale");
break;
}
Le versioni moderne di C# introducono la switch expression, una forma più concisa che restituisce direttamente un valore. Il simbolo => associa ogni caso al suo risultato e il carattere di sottolineatura rappresenta il caso predefinito.
// La switch expression restituisce un valore
string dayType = day switch
{
1 or 2 or 3 or 4 or 5 => "Feriale",
6 or 7 => "Weekend",
_ => "Non valido"
};
Il ciclo for
Il ciclo for è ideale quando si conosce in anticipo il numero di ripetizioni. È composto da tre parti separate da punto e virgola: l'inizializzazione, la condizione di continuazione e l'aggiornamento eseguito al termine di ogni iterazione.
// Stampa i numeri da 0 a 4
for (int i = 0; i < 5; i++)
{
Console.WriteLine(i);
}
I cicli while e do-while
Il ciclo while ripete un blocco finché una condizione resta vera, valutandola prima di ogni iterazione. Il ciclo do-while è simile, ma valuta la condizione alla fine, garantendo così che il blocco venga eseguito almeno una volta.
// while: verifica la condizione prima di eseguire
int count = 0;
while (count < 3)
{
Console.WriteLine($"Iterazione {count}");
count++;
}
// do-while: esegue almeno una volta
int attempts = 0;
do
{
Console.WriteLine("Tentativo eseguito");
attempts++;
} while (attempts < 1);
Il ciclo foreach
Il ciclo foreach attraversa gli elementi di una collezione senza dover gestire manualmente un indice. È la forma preferita quando si vuole semplicemente esaminare ogni elemento in sequenza, perché è più chiara e meno soggetta a errori.
string[] languages = { "C#", "Go", "Python" };
foreach (string language in languages)
{
Console.WriteLine(language);
}
Controllare il flusso: break e continue
All'interno di un ciclo, l'istruzione break interrompe immediatamente il ciclo, mentre continue salta il resto dell'iterazione corrente e passa alla successiva. Entrambe permettono un controllo fine del flusso.
for (int i = 0; i < 10; i++)
{
if (i == 5)
{
break; // interrompe il ciclo quando i vale 5
}
if (i % 2 == 0)
{
continue; // salta i numeri pari
}
Console.WriteLine(i); // stampa solo 1 e 3
}
Conclusione
Abbiamo visto come gli operatori aritmetici, relazionali e logici permettano di calcolare e confrontare i valori, e come gli operatori dedicati ai nulli rendano il codice più conciso e sicuro. Abbiamo poi esplorato le strutture di controllo che governano il flusso: le decisioni con if e switch, incluse le loro forme moderne come espressioni, e i cicli for, while, do-while e foreach, insieme al controllo fine offerto da break e continue. Nel prossimo articolo impareremo a organizzare il codice in metodi, per renderlo riutilizzabile e ben strutturato.