C# - Fondamenti del linguaggio C#
Il CLR, l'IL e il JIT
- I programmi creati con C#, possono essere eseguiti solo su macchine che hanno il .NET Common Language Runtime (CLR). In caso contrario, semplicemente non vengono eseguiti.
- Il beneficio principale è la portabilità. Programmi creati con altri linguaggi, per poter essere eseguiti su macchine Windows e Linux, devono essere compilati con due compilatori diversi. Un programma compilato con C# produce un file in Intermediate Language (IL) che può essere copiato da una macchina all’altra. Esso non è eseguibile direttamente ma tramite il CLR.
- Il CLR quindi compila solo la parte di codice che deve essere eseguita e l’esito della compilazione è il Just In Time (JIT) o jitting.
- La versione del CLR non va di pari passo con quella del C#, né con quella del Framework. Al momento esistono le sole versioni 2.0 e 4.0. Per trovare le versioni installate sulla macchina, dal prompt dei comandi di Visual Studio, dare il comando clrver. Il risultato dovrebbe essere:
Versions installed on the machine:v2.0.50727v4.0.30319
- L’esecuzione di un programma C# è inizialmente più lenta di un programma scritto per esempio in C++ in quanto occorre compilarlo in linguaggio macchina, ma una volta che una parte di codice è stata compilata, la sua esecuzione è veloce come quella in altri linguaggi.
- Il C# è case sensitive.
- Le variabili vanno sempre dichiarate e inizializzate. Il primo carattere può essere una lettera, l'underscore ("_") oppure l'at ("@").
- Terminare le istruzioni con ";".
- Nella tabella seguente vengono riassunti i tipi di dati primitivi.
Tipo di dato C# |
Tipo di dato .NET |
Dim. (byte) |
Val. minimo |
Val. massimo |
sbyte |
System.Sbyte |
1 |
-128 |
127 |
byte |
System.Byte |
1 |
0 |
255 |
short |
System.Int16 |
2 |
-32,768 |
32,767 |
ushort |
System.UInt16 |
2 |
0 |
65,535 |
int |
System.Int32 |
4 |
-2,147,483,648 |
2,147,483,647 |
uint |
System.UInt32 |
4 |
0 |
4,294,967,295 |
long |
System.Int64 |
8 |
-9,223,372,036,854,775,808 |
9,223,372,036,854,775,807 |
ulong |
System.UInt64 |
8 |
0 |
18,446,744,073,709,551,615 |
char |
System.Char |
2 |
0 |
65,635 |
float |
System.Single |
4 |
-3.4e38 |
-1.5e-45 |
1.5e-45 |
3.4e38 |
|||
double |
System.Double |
8 |
-1.7e308 |
-5.0e-324 |
5.0e-324 |
1.7e308 |
|||
decimal |
System.Decimal |
16 |
+/-1.0e-28 |
+/-7.9e28 |
bool |
System.Boolean |
1 |
false (0) |
true (1) |
- I tipi di dati sbyte, byte, short, ushort, int, uint, long e ulong, sono adatti a contenere numeri interi.
- I tipi di dati float, double e decimal, sono adatti a contenere numeri decimali. Il float e il double memorizzano numeri nel formato mantissa e esponente a base 2, mentre il decimal memorizza numeri nel formato mantissa e esponente a base 10.
- I valori con virgole sono sempre double; i valori senza virgole sono sempre int. Questa regola vale sempre eccetto nel caso che dopo il numero sia indicato un suffisso.
- Il float ha una precisione di circa 7 cifre decimali. Per utilizzarlo deve essere seguito da 'F' o 'f':
- Il double ha una precisione da 14 a 16 cifre decimali. Per utilizzarlo deve essere seguito da 'D' o 'd' o niente perché un decimale per default è un double:
- Il decimal ha una precisione da 28 a 29 cifre decimali. Per utilizzarlo deve essere seguito da 'M' o 'm':
- Elenco di tutti i suffissi:
- uint: u, U
- long: l, L
- ulong: ul, Ul, uL, UL, lu, Lu, lU, LU
- float: f, F
- double: nessuno, d, D
- decimal: m, M
Operatori e operazioni
- Nella tabella seguente ci sono gli operatori:
Operatore | Descrizione |
= | Assegnazione |
+, -, *, / | Operatori aritmetici |
% | 'Resto' della divisione |
+ | Concatena stringhe |
++ | Incrementa, può essere prefisso o postfisso |
-- | Decrementa, può essere prefisso o postfisso |
== | Uguaglianza |
!= | Disuguaglianza |
<, <=, >, >= | Minore, minore o uguale, maggiore, maggiore o uguale |
&, && | Operatori logici AND e AND corto circuito |
|, || | Operatori logici OR e OR corto circuito |
^ | Operatore logico XOR |
op1 ? op2 : op3 | Operatore ternario equivalente a: if(op1) return op2; else return op3; |
?? | Operatore null coalescing; per esempio: var ret = exp1 ?? exp2 ?? expDefault assegna a ret la prima espressione non nulla tra exp1, exp2 e expDefault |
?. | Operatore null conditional; per esempio: int? len=str?.Length; assegna a variabile len (che nullable, cioè può assumere un valore nullo) la lunghezza della stringa str, solo se non nulla |
nameof() | Operatore introdotto in C#6, restituisce il nome di un elemento di codice (variabile, tipo, membre, ...) |
is | L'operatore (restituisce true o false) verifica se una variabile è di un certo tipo o se è convertibile in un certo tipo. Esempi: public class c1 { } public class c2 : c1 { }
c1 object1 = new c1();
c2 object2 = new c2();
Console.WriteLine(object1 is c1); // True
Console.WriteLine(object2 is c2); // True
Console.WriteLine(object1 is c2); // False Console.WriteLine(object2 is c1); // True |
as | L'operatore permette la conversione di un oggetto in un tipo se la conversione è possibile, altrimenti restituisce un null. Esempio (con le stesse classi definite sopra): c2 object2 = object1 as c2; |
- Nella tabella seguente vengono riassunte le precedenze tra gli operatori.
Categoria |
Operatore |
Descrizione |
Primari |
() |
Override con precedenza |
++ |
Pre/Post-incremento |
|
-- |
Pre/Post-decremento |
|
Unari |
! |
Not logico |
+ |
Addizione |
|
- |
Sottrazione |
|
Moltiplicativi |
* |
Moltiplicazione |
/ |
Divisione |
|
% |
Resto della divisione |
|
Addizionali |
+ |
Addizione |
- |
Sottrazione |
|
Relazionari |
< |
Minore |
<= |
Minore o uguale |
|
> |
Maggiore |
|
>= |
Maggiore o uguale |
|
Di uguaglianza/disuguaglianza |
== |
Uguale |
!= |
Non uguale |
|
And logico |
& e && |
AND logico |
Or logico |
| e || |
OR logico |
Xor logico |
^ |
XOR logico |
Assegnazione |
= |
Assegnazione |
Caratteri di escape
- Nella tabella seguente sono elencati i caratteri di escape.
Carattere |
Descrizione |
Carattere Unicode |
\a |
Segnale sonoro (Alert) |
0x0007 |
\r |
Ritorno a capo (carriege return) |
0c00D |
\n |
Nuova linea (new line) |
0x000A |
\f |
Avanzamento pagina (form feed) |
0x000C |
\t |
Tabulazione orizzontale |
0x0009 |
\v |
Tabulazione verticale |
0x000B |
\b |
Backspace |
0x0008 |
\\ |
Backslash |
0x005C |
\' |
Apice singolo |
0x0027 |
\" |
Apice doppio |
0x0022 |
\0 |
Null |
0x0000 |
Le versioni del Framework
- Nella tabella seguente sono elencate le versioni Framework e del C# con le caratteristiche introdotte.
Anno | Versione .Net | Versione C# | Caratteristiche introdotte |
2002 | .Net 1 | C# 1 | Classi, Struct, Interfacce, Eventi, Proprietà, Delegati Operatori ed espressioni, Istruzioni, .Attributes (Attributi) |
2003 | .Net 1.1 | C# 1.2 | |
2005 | .Net 2 | C# 2 | Generics, Tipi parziali, Metodi anonimi, Tipi valore nullable, Iterators, Covarianza e controvarianza. |
2006 | .Net 3 | N/A | |
2007 | .Net 3.5 | C# 3 | Proprietà implementate automaticamente, Tipi anonimi, Espressioni di query, Espressioni lambda, Alberi delle espressioni, Metodi di estensione, Variabili locali tipizzate in modo implicito, Metodi parziali, Inizializzatori di oggetto e di raccolta. |
2010 | .Net 4 | C# 4 | Associazione dinamica, Argomenti denominati/facoltativi, Covarianti e controvarianti generiche, Tipi di interoperabilità incorporati. |
2012 | .Net 4.5 | C# 5 | |
2013 | .Net 4.5.1 .Net 4.5.2 | C# 5 | Membri asincroni, Attributi informativi sul chiamante. |
2015 | .Net 4.6 .Net 4.6.1 .Net 4.6.2 | C# 6 | Importazioni statiche, Filtri eccezioni, Inizializzatori di proprietà automatiche, Membri con corpo di espressione, Propagazione Null, Interpolazione di stringhe, Operatore nameof. |
2017 | .Net 4.7 .Net 4.7.1 | C# 7 C# 7.1 C# 7.2 C# 7.3 | Variabili out, Tuple e decostruzione, Criteri di ricerca, Funzioni locali, Membri di espressioni corpo espansi, Variabili locali e valori restituiti per riferimento. |
.Net Core | C# 8 | Membri di sola lettura, Metodi di interfaccia predefiniti, Miglioramenti dei criteri di ricerca, Uso delle dichiarazioni, Funzioni locali statiche, Struct ref Disposable, Tipi riferimento nullable, Flussi asincroni, Indici e intervalli, Assegnazione null-coalescing, Tipi costruiti non gestiti, Stackalloc nelle espressioni annidate, Miglioramento delle stringhe verbatim interpolate. | |
.Net 5 | C# 9 | Record, Setter di sola inizializzazione, Istruzioni di primo livello, Miglioramenti dei criteri di ricerca, Prestazioni e interoperabilità, Adattare e completare le funzionalità, Supporto per generatori di codice. | |
C# 10 | Struct di record, Miglioramenti dei tipi di struttura, Gestori di stringhe interpolate, Direttive, Dichiarazione dello spazio dei nomi con ambito file, Modelli di proprietà estese, Miglioramenti alle espressioni lambda, Consenti stringhe interpolate I tipi di record possono bloccare, Assegnazione definita migliorata, Consentire sia l'assegnazione che la dichiarazione nella stessa decostruzione, Consenti attributo nei metodi, Attributo CallerArgumentExpression, Pragma avanzato. |
Debug dei programmi
- Quando si programma è utile scrivere delle informazioni (valori di variabili per esempio) da qualche parte per verificare se il programma si comporta come progettato.
- Si può utilizzare la classe 'Debug' contenuta in 'System.Diagnostics'.
- Tra i vari metodi, i più interessanti sono 'WriteLine' (con due overload) e 'WriteLineIf'.
for (int i = 0; i < 10; i++)
{
Debug.WriteLine("Debug Ciclo numero " + i);
Debug.WriteLine("Debug Ciclo numero " + i, "Categoria");
Debug.WriteLineIf(i % 2 == 0, i);
}
- L'esempio precedente mostra alcuni utilizzi della classe Debug.
- Le stringhe sono scritte nella finestra 'Output'.
- Output della prima riga:
Debug Ciclo numero 0
...
Debug Ciclo numero 9
- Output della seconda riga:
...
Categoria: Debug Ciclo numero 9
- Output della terza riga:
2
4
6
8