IlC# (pronuncia inglese:[ˈsiː ˈʃɑːp], come l'espressionesee sharp, "vedere nitidamente")[1] è unlinguaggio di programmazione multi-paradigma che supporta tutti i concetti della programmazione orientata agli oggetti. Esso è stato sviluppato daMicrosoft all'interno dell'iniziativa.NET, e successivamente approvato come standard dallaECMA (ECMA-334) eISO (normaISO/IEC 23270).
Il progettista principale di C# èAnders Hejlsberg, un informatico danese precedentemente coinvolto nello sviluppo dei linguaggiTurbo Pascal e BorlandDelphi (attualmente di proprietà di Embarcadero).
È opinione comune che l'ispirazione venne dal linguaggioJava, dato che perfino il suo ideatoreJames Gosling, nonchéBill Joy di Sun Microsystem, lo definirono una sua imitazione, ma più limitata dal punto di vista dell'affidabilità, della sicurezza e della produttività[2]. Invece, secondo Anders Hejlsberg e Microsoft stessa, la struttura di C# è più vicina a quella dellinguaggio C++ di quella diJava[3].
C# è strettamente legato allo sviluppo di.NET Framework. Infatti gli ingegneri di Microsoft utilizzarono nelle prime fasi della sua stesura un framework chiamato SMC, ovvero Simple Managed C, un sistema utilizzante illinguaggio C in modo gestito o "managed". Nel gennaio 1999,Microsoft mise Anders Hejlsberg a capo di un gruppo di lavoro con il compito di produrre un nuovo linguaggio, chiamato provvisoriamente "Cool", acronimo di "C-like Object Oriented Language" (linguaggio orientato agli oggetti simile a C)[4]. Il nome commerciale definitivo divenne C# alla presentazione ufficiale del progetto .NET da parte di Microsoft alla Professional Developers Conference tenutasi nelluglio2000 aOrlando, quando anche lelibrerie di classi e il runtime diASP.NET vennero convertite in linguaggio C#.
Nel tempo C# eJava hanno percorso strade differenti, aumentando complessivamente le differenze reciproche, sebbene ci siano stati anche evidenti casi di reciproco scambio di caratteristiche. Per esempio C#, a differenza di Java, utilizza sin dalla versione 2 lareificazione per generare oggetti generici che possono essere usati come classi, riservando al momento del caricamento della classe in fase di esecuzione la compilazione effettiva del codice. Anche l'implementazione in ambedue i linguaggi deitipi generici, sebbene concettualmente identica, è stata implementata in maniera piuttosto differente. Invece, il concetto di boxing e unboxing propri di C# sono stati implementati successivamente anche in linguaggio Java[5].
La versione C# 1.0, basata su .NET Framework 1.0, fu pubblicata commercialmente da Microsoft nel gennaio 2002 con il pacchetto di sviluppo Visual Studio .NET 2002. In seguito sono state pubblicate sino ad oggi nuove versioni del linguaggio e del framework .NET con i pacchettiMicrosoft Visual Studio.[6]
C# è, in un certo senso, il linguaggio che meglio degli altri descrive le linee guida sulle quali ogni programma.NET gira. Infatti è stato creato daMicrosoft specificatamente per la programmazione nelframework.NET. I suoi tipi di dati "primitivi" hanno una corrispondenza univoca con i tipi.NET e molte delle sue astrazioni, comeclassi,interfacce,delegati edeccezioni, sono particolarmente adatte a gestire il framework .NET. È divenuto quindi il linguaggio ordinario per realizzare software in ambiente Windows.
Definire in forma classica C# come linguaggio interpretato o compilato nel senso classico dei termini è piuttosto complicato. In effetti è ambedue le cose allo stesso tempo. Data la sua stretta integrazione con il framework .NET, i codici sorgente scritti in C# sono normalmente compilati secondo i criteriJIT. In pratica, la trasformazione in codice macchina (ovvero eseguito direttamente dallaCPU) viene compiuta solo all'atto di caricamento ed esecuzione del programma. In prima istanza ilcodice sorgente viene convertito dal framework in un codice intermedio dettoCIL e solo all'esecuzione del programma ilCLR specifico per ilsistema operativo utilizzato converte il CIL inlinguaggio macchina specifico per l'hardware ospite, man mano che viene eseguito. Ciò comporta che l'esecuzione del codice può risultare più lenta alla prima esecuzione diventando poi più veloce. Inoltre, vengono tipicamente svolte durante la compilazione stessa delle ottimizzazioni progressive del codice macchina, producendo così un codice eseguito più velocemente e teoricamente "ottimale" solo dopo alcune esecuzioni complete dello stesso.
Una seconda possibilità è la cosiddettacompilazione Ngen, che permette di convertire tutto il codice CIL in codice macchina in una volta sola. Ciò ha il vantaggio di consentire l'implementazione di ambienti di sviluppo che utilizzino C# in qualunque sistema operativo, una volta implementato ilCLR specifico.
La sintassi di base del C# è spesso molto simile o identica a quella dei linguaggi C, C++ e Java. Alcune delle caratteristiche di base sono:
I nomi di variabili, funzioni, classi e altri elementi sono sempre sensibili alle minuscole, ovvero "case-sensitive".
Ogni specifica dev'essere chiusa dal caratterepunto e virgola (;).
Gli indici degli elementi diarray ematrici sono numerati a partire da 0.
Le parentesi graffe ({}) sono usate per raggruppare specifiche.
Secondo le consuetudini dei linguaggi orientati agli oggetti, le specifiche sono di regola raggruppate inmetodi (ovvero funzioni), imetodi sono raggruppati inclassi, e leclassi sono raggruppate neinamespace.
Rispetto aC o aC++ il linguaggio C# presenta varie modifiche, volte principalmente ad evitare errori tipici e ambiguità della programmazione inlinguaggio C:
I puntatori possono essere utilizzati solo in particolari blocchi di codice marcati comeunsafe.
In molte operazioni aritmetiche vengono controllati eventualioverflow.
Gli oggetti dinamici non vengono deallocati esplicitamente, ma viene gestita automaticamente e implicitamente dalgarbage-collector quando non esistono più riferimenti a tali oggetti. Questo sistema evita i due problemi deidangling pointer e delmemory leak, anche se con una riduzione delle prestazioni.
Come inJava è possibile ereditare da una sola classe, diversamente da quanto avviene inC++, ma è possibile implementare un numero indefinito diinterfacce. A differenza delC++, non è consentita l'ereditarietà di tipoprivate.
Le sole conversioni implicite consentite sono quellesafe, ovvero che non espongono al rischio di perdita di dati causata dal diverso tipo di dato. Per esempio non sono consentite conversioni implicite frainteger eboolean oppure tra enumeratori edinteger.
C# non dispone deitemplate tipici delC++, ma nella versione 2.0 sono stati introdotti igeneric.
Sebbene C# sia ritenuto simile aJava, esistono alcune importanti differenze fra i due linguaggi. Quella maggiormente visibile è certamente la presenza in C# di molti costrutti, alcuni dei quali chiaramente derivati dalC++, che inJava sono stati deliberatamente vietati. I sostenitori del C# affermano che tutto ciò rende il codice più chiaro, mentre i sostenitori diJava affermano che proprio la presenza di un gran numero di parole-chiave e di regole da ricordare rende il linguaggio più difficile da imparare e utilizzare.
Altre differenze evidenti sono le seguenti:
Java utilizza i commenti Javadoc-sintax per generare la documentazione dal codice sorgente, mentre C# utilizza la sintassiXML nei commenti per lo stesso scopo.
Quello che inJava è chiamatopackage, in C# viene chiamatonamespace o "spazio di nomi". Un ulteriore livello di organizzazione in C# è costituito dagliassembly, che possono contenere al proprio interno diversi spazi di nomi.
Java utilizza un diverso modo per richiamare i metodi costruttori di una classe, ovvero dalla prima riga di un costruttore ne richiama un altro.
Il seguente esempio visualizza il testo "Hello world" su console.
usingSystem;classHelloWorldApp{publicstaticvoidMain(string[]args)// punto d'ingresso del programma{Console.WriteLine("Hello World");Console.ReadLine();}}
Invece il seguente esempio stampa il testo "Hello world" in una Message Box.
Il seguente esempio definisce una classe di nome Persona che espone una proprietàNome il cui valore viene memorizzato nella variabilemNome:
usingSystem;namespaceProgram{classPersona{privatestringmNome;//se non specifico "private" non ci sono differenze, perché è sottinteso.publicstringNome{get{returnmNome;}set{mNome=value;}}}}
Lo stesso esempio si può scrivere in una forma equivalente, utilizzando la sintassi delleAutomatic Properties introdotta con la versione 3.0:
Da notare che il linguaggio C# risulta uno strumento sintattico per l'utilizzo delle librerie presenti nei namespace del Framework.NET diMicrosoft. A parte le strutture interne al linguaggio, il programmatore C# deve fare riferimento alle librerie, anche per la gestione dell'I/O, come del resto in C e C++. Infatti, nel primo esempio presentato viene utilizzato il namespaceSystem del quale sarà poi utilizzato il metodoWriteLine della classeConsole per scrivere a video la scritta "Hello World".
In questo esempio si utilizza il namespace nativoSystem.Text.Json per deserializzare un semplice file JSON, il cui contenuto viene in seguito formattato e stampato suSystem.Console.
Prendiamo in considerazione il seguente JSON.
{"0":"Carthago delenda est.","1":"Alea iacta est.","2":"Cogito ergo sum."}
Questo il codice in C#.
usingSystem.Text.Json;namespaceJSONDeserialization;classProgram{// Creiamo un'istanza di "JsonSerializerOptions.Default".// È sempre consigliato inizializzarne solo una per programma.// La parola chiave "readonly" significa che la variabile non verrà modificata dopo l'inizializzazione.privatereadonlystaticJsonSerializerOptionsJsonOptions=JsonSerializerOptions.Default;// La funzione riceve come parametro la directory del file JSON che vogliamo deserializzare.// Ci ritorna un dizionario contenente chiavi, identificatori unici di tipo "Int32", e un valore di tipo "String" per ogni chiave.privatestaticDictionary<int,string>GetJsonAsDictionary(stringdirectory){// Dichiariamo un dizionario vuoto e nullable.Dictionary<int,string>?data=[];// Deserializziamo il file usando questa funzione statica e specificando il tipo di ritorno.// Alcune funzioni richiedono che venga specificato il tipo di ritorno tra due parentesi angolari.data=JsonSerializer.Deserialize<Dictionary<int,string>>(File.ReadAllText(directory),JsonOptions);// File è una classe statica fornita da System per semplici manipolazioni di file.// Se il dizionario è nullo o vuoto, facciamo scattare una "Exception".// Le "Exception" spezzano immediatamente il runtime flow di un programma.if(dataisnull||data.Keys.Count==0)thrownewException("Il file è vuoto o non è stato deserializzato correttamente.");returndata;}privatestaticvoidMain(){// Infine usiamo "string.Join" per scrivere l'output della funzione sulla Console.Console.WriteLine(string.Join(", ",GetJsonAsDictionary("test.json")));}}
L'output sarà quindi:[0, Carthago delenda est.], [1, Alea iacta est.], [2, Cogito ergo sum.]
usingSystem;namespaceCalcolatrice{classProgram{staticvoidMain(string[]args){intNumero1=0,Numero2=0;// Dichiara due numeri e li inizializza a 0.intRisultato;// Variabile che serve per il risultato dei due numeri.charScelta;// Scelta dell'utente riferito alle opzioni nel menù.do{Console.Clear();// Cancella tutte le scritte presenti nella console./* Menù */Console.WriteLine("Benvenuto nella calcolatrice.");// Scrive nella console "Benvenuto nella calcolatrice.".Console.WriteLine("1. Addizione");// Scrive nella console "1. Addizione".Console.WriteLine("2. Sottrazione");// Scrive nella console "2. Sottrazione".Console.WriteLine("3. Moltiplicazione");// Scrive nella console "3. Moltiplicazione".Console.WriteLine("4. Divisione");// Scrive nella console "4. Divisione".Console.WriteLine("5. Esci");// Scrive nella console "5. Esci".Scelta=Console.ReadKey().KeyChar;// L'opzione dell'utente viene memorizzata nella variabile "Scelta"Console.Clear();// Cancella tutte le scritte presenti nella console.if(Scelta!='5'){Console.Write("Inserisci il Primo numero: ");// Chiede all'utente di inserire il primo numero.Numero1=Convert.ToInt32(Console.ReadLine());// Assegna il primo numero inserito dall'utente alla variabile "Numero1".Console.Write("Inserisci il secondo numero: ");// Chiede all'utente di inserire il secondo numero.Numero2=Convert.ToInt32(Console.ReadLine());// Assegna il secondo numero inserito dall'utente alla variabile "Numero2".}switch(Scelta)// Con lo switch si analizzano i vari casi del valore della variabile.{case'1':{Risultato=Numero1+Numero2;// Il risultato dell'addizione va a finire dentro alla variabile "Risultato".Console.WriteLine(Numero1+" + "+Numero2+" = "+Risultato);// Dice all'utente il risultato.break;// Termina subito lo switch per non fare anche gli altri casi}case'2':{Risultato=Numero1-Numero2;// Il risultato della sottrazione va a finire dentro alla variabile "Risultato".Console.WriteLine(Numero1+" - "+Numero2+" = "+Risultato);// Dice all'utente il risultato.break;// Termina subito lo switch per non fare anche gli altri casi}case'3':{Risultato=Numero1*Numero2;// Il risultato della moltiplicazione va a finire dentro alla variabile "Risultato".Console.WriteLine(Numero1+" * "+Numero2+" = "+Risultato);// Dice all'utente il risultato.break;// Termina subito lo switch per non fare anche gli altri casi}case'4':{if(Numero2!=0)// La divisione per zero è impossibile quindi si aggiunge un if{Risultato=Numero1/Numero2;// Il risultato della divisione va a finire dentro alla variabile "Risultato".Console.WriteLine(Numero1+" / "+Numero2+" = "+Risultato);// Dice all'utente il risultato.}else{Console.WriteLine(Numero1+" / "+Numero2+" = Impossibile!");// Risultato impossibile}break;// Termina subito lo switch per non fare anche gli altri casi}case'5':{break;// Termina subito lo switch per non fare anche gli altri casi}default:{Console.WriteLine("Opzione Errata");break;}}Console.WriteLine("Premere invio per andare avanti");Console.ReadKey();}while(Scelta!='5');// Se la condizione è vera il codice al suo interno viene rieseguito!}}}
Il progettoMono implementa un compilatore C# con licenzaopen source, un'implementazione completaopen source delCLI, oCommon Language Infrastructure, comprendente le librerie di framework richieste da specificheECMA, oltre a una quasi completa implementazione delle librerie di classi proprietarie di.NET attualmente aggiornate alla versione 3.5. Fino alla versione 2.6 di Mono non è prevista l'implementazione diWindows Presentation Foundation (WPF), sebbene sia invece prevista per successive evoluzioni della piattaforma Mono. Inoltre attualmente sono previste implementazioni solo parziali diLINQ to SQL eWCF.
Il progettoDotGNU, attualmente non più supportato[14], include un compilatore C#, una implementazione parziale dellaCLI, comprese le librerie richieste secondo le specificheECMA, oltre a un sottoinsieme di alcune librerie di classi.NET proprietarie di Microsoft, aggiornate alla versione .NET 2.0.
Il progetto Rotor di Microsoft, distribuito con licenza gratuita solo per scopi didattici e di ricerca, fornisce una implementazione del runtime CLR e un compilatore C#, con un sottoinsieme dell'infrastruttura CLI conforme alle specifiche ECMA[15].
↑Il nome gioca sul fatto che C♯, in inglese e altre lingue, indica la nota musicale Do diesis, un semitono sopra il "C", ovvero il Do (fonte: James Kovacs,C#/.NET History Lesson, sujameskovacs.com, 7 settembre 2007.URL consultato il 7 giugno 2012(archiviato dall'url originale il 21 agosto 2011).). In effetti, il nome del linguaggio andrebbe scritto con il simbolo deldiesis, ma in sostituzione si usa ilcancelletto per praticità di scrittura (fonte:MSDN,Domande frequenti su Visual C#). In italiano, il gioco di parole viene perso.
D. Bochicchio, C. Civera, M. De Sanctis, A. Leoncini, M. Leoncini, S. Mostarda,C#6 e Visual studio 2015. Guida completa per lo sviluppatore, Hoepli Informatica, 2016, p.456,ISBN978-88-203-7099-2.
Antonio Pelleriti,Programmare con C# 8. Guida completa, Edizioni LSWR, 2019, p.928,ISBN978-88-68957698.
(EN) A. Troelsen, P. Japikse,C# 6.0 and the .NET 4.6 Framework, Apress, 2016, p.1625,ISBN978-1-4842-1333-9.
(EN) J. Albahari, B. Albahari,C# 6.0 in a Nutshell: The Definitive Reference, O'Reilly Media, 2016, p.1136,ISBN978-1-4919-2706-9.
(IT) A. Pelleriti Programmare con C# 8, Digital Life Style, p.243,ISBN 978-88-6895-769-8