Il C# (si pronuncia see sharp) è un linguaggio di programmazione orientato agli oggetti sviluppato da Microsoft all'interno dell'iniziativa .NET, e successivamente approvato come standard dalla ECMA (ECMA-334) e ISO (norma ISO/IEC 23270).
La sintassi e struttura del C# prendono spunto da vari linguaggi nati precedentemente, in particolare Delphi, C++, Java e Visual Basic.
In questa guida vediamo la versione 7.2 di C#.
.Object-Oriented, sintassi alla C (graffe, int, for, ...)
.Distinzione fra tipi valore e reference
- boxing e unboxing
- le stringe sono oggetti immutabili
.Ereditarietà singola per classi, ma multipla per le interfacce. Supporta i generici (metodi, classi, e interfacce)
.Costruttori per inizializzare gli oggetti
.Oggetti creati con new, garbage collected
.Gestione degli errori tramite meccanismo di eccezioni
.Compilato per un'unica architettura (virtuale)
Statement
.if, while, do while, for, {}, expression-stmt (espresesione seguita da ";"), dichiarazioni di tipo sono (quasi) uguali.
.foreach(T v in exp) che in Java è for(T v : exp)
.goto (permesso in certi casi), sostanzialmente sostituisce break/continue etichettati
.synchronized è diventato lock
.Lo switch
- non supporta il "fall-through" se il case non è completamente vuoto
- i case possono essere string literal (ora anche in Java 7)
- (supporta anche i pattern matching nei case)
Java C# (in realtà: .NET) java.lang.Object: System.Object: -toString -ToString -equals -Equals -hashCode -GetHashCode -(finalize) -(finalize) -(altri metodi coi thread) java.lank è un package System è un namespace (java -> classe di java.lang) -che si importano -si dichiarano con namespace e si usano con using
Vediamo il primo codice Ciao Mondo:
namespace ConsoleApplication { using System; public class Program { public static void Main(string[] args) { Console.WriteLine("ciao mondo"); Console.ReadLine(); } }}
si può usare il comando
using static System.Console;
Permette di usare le classi dichiarate in System senza qualificarle pienamente Console invece di System.Console;
Meccanismo analogo per le classi permette di accedere ai membri statici senza esplicitare il nome della classe WriteLine invece di Console.WriteLine
Modificatori di Accesso
Le classi possono avere questi modificatori di accesso vediamo il confronto con Java:
Java c#
.public .public
.protected .protected - classe e sottoclassi
.(friendly) .---
.--- .internal - stesso assembly (dll o exe)
.--- .internal protected - protected o internal
.--- .private protected - protected e internal (sic)
.private .private
public: accessibile a tutti
private: accessibile solo alla classe
Ereditarietà
Vediamo prima come si fa in Java prima:
Java
.class C1 extends C2
implements l1, l2, l3 {
C1() super(...) ...
C1 (int x) { this(...) ...
interface l extends l1, l2, l3, ..
In Java le interfacce possono avere campi costanti (final static)
ora vediamo l'ereditarietà in C#:
c#
class C1 : C2, I1, I2, I3 {
C1 : BASE (...) { ...
C1 (int x) : this (...) { ..
interface I : I1, I2, I3 ...
In C# le interfacce contengono solo metodi (astratti e pubblici, come in Java)
Per convenzione, iniziano tutte con I : IPippo, IPluto, ecc..
Metodi virtuali o no?
JAVA:
. default: dispatch dinamico
. override senza modificatori (ma introdotta @Override)
. final rende il dispatch statico, ma evita anche ogni ri-definizione nelle sottoclassi
Binding: associazione di un nome a un'operazione (usando, per esempio, i tipi degli operandi/argomenti) in Java sempre statico
in C# Dynamic binding -> dynamic dispatch (non viceversa!)
Dynamic dispatch: selezione di una particolare implementazione per operazione polimorfa
C#:
. default: dispatch statico
. per avere dispatch dinamico: virtual
. quando il metodo esiste già, richiesto override o new (che è default, ma con warning)
. una ridefinizione di metodo può essere marcata con sealed per evitare altre ridefinizioni
. classe sealed è come final in Java
Metodi implementati
Se I1 e I2 hanno un metodo m, e C le implementa entrambe, posso implementare diversamente I1.m e I2.m?
In Java No, è richiesto un metodo pubblico chiamato m e ce ne può essere solo uno
In C# si, grazie all'implementazione esplicita di interfacce
public class C : I {
int I.Met() {
return 1;
}
}
Non ci va nessun modificatore e il metodo risulta inaccessibile attraverso il tipo C.
Metodi locali
I metodi locali sono sempre privati, dentro a Met stesso, come convenzione di stile si mettono in fondo
Non sono visibili agli altri metodi e chi deve capire la classe sa che non ha bisogno di leggerli se non vuole entrare nei dettagli di Met
Runtime Type Identification/Cast
in Java abbiamo;
- exp instanceof T
- (T)exp
- Object t = exp; t instanceof T ? (T)exp : (T)null
in C# abbiamo:
- exp is T
- (T)exp
- exp as T
Costanti
Java
.Campi final static
C#
.Modificatore readonly analogo a final
.Modificatore const, usabile con tipi numerici ed enumerazioni, indica una costante a tempo di compilazione
Eccezioni
Entrambi hanno try/catch/finally e una gerarchia di eccezioni con radice (java.lang/System).Exception e membri analoghi StackTrace/InnerException
Ma C# non ha le eccezioni controllate, quindi non ha la clausola throws nelle intestazioni dei metodi (e non vi costringe a dichiarare/catturare)
Le eccezioni si catturano per gestirle
catch (Exception e) {Console.WriteLine(e.Message);}
eventualmente si risollevano
Catch (Exception e) {throw new Exception (e.Message); }
magari cambiando tipo
catch (Exception e) {throw new MyException(e.Message);}
Ok solo per console applications
Altrimenti:
catch (Exception e)
{
Debug.WriteLine(e.Message);
}
cosi si conserva history
Oppure usando gli exception filter:
private static bool NotifyAndContinue(Exception e){ /*do logging/console writing*/ return false; } ... catch (Exception e) when (NotifyAndContinue(e)) { }
volendo cambiare tipo
catch (Exception e) {throw new MyEception(e);}
Tipi primitivi/valore
Java:
boolean, char, int, long, float, double, ...
C#:
bool, char, int, long, float, double, (unsigned) uint, ulong, ...
ma int è un alias di Int32, ulong di UInt64, ecc...
- object è un alias di Object
- string è un alias di String
Tipi in .NET
I linguaggi supportati dal .NET framework quali C# e VB si dice che sono strongly-typed, ossia fortemente tipizzati, in parole povere ogni variabile od oggetto dichiarato all'interno del programma deve definire un tipo e lo deve rispettare (pena un errore di compilazione).
Valore
- Le variabili memorizzano direttamente gli oggetti, non è possibile aliasing
Questi tipi rappresentano la stragrande maggioranza dei Tipi Primitivi (dati a sè stanti e non complessi, come un numero o un carattere), come System.Int16, System.Char, System.Boolean, System.DateTime.
il valore del dato il quale viene allocato nella zona di memoria detta stack
Reference
- Le variabili memorizzano dei riferimenti a oggetti, l'assegnazione crea degli alias
Questi tipi rappresentano tutti quei dati espressi tramite la dichiarazione di classi per descrivere oggetti complessi, essi vengono allocati nella memoria managed heap e non contengono direttamente il valore del dato, ma un puntatore ad una locazione di memoria dove è contenuto il valore vero e proprio, infine come è facile presumere questi possono assumere valore null.
C#: struct, tipi di valore
In c# è possibile creare i propri tipi valore usando struct
I tipi valore possono essere allocati sullo stack, no aliasing
Enum
Simili a quelli di C/C++, un modo per definire delle costanti di tipo integrale
internal enum Color { Red, Green, Blue, } Color c=Color.green;
Rilascio automatico delle risorse:
using (var pippo=new StreamReader(@"c:\bla")) { //usa pippo... }
Generici
Simili a quelli Java (ma molto efficienti)
Si possono mettere dei vincoli sugli argomenti tramite la clausola where
public class C<T> where T : new() { public T Foo() { return new T(); } }
Generici, vincoli
- new(): l'argomento deve essere un tipo instanziabile, col costruttore di default
- Atype: l'argomento deve essere sottotipo di AType, può essere il nome di un tipo del sistema o di un altro parametro del generico
- struct: l'argomento deve essere un value type
- class: l'argomento deve essere un tipo refernce (classe, interfaccia, delegate o array)
Se si devono vincolare più argomenti, servono più clausole where
class Test<T,U> where U : struct where T : E, new() { }
Un parametro di tipo di un'interfaccia (o delegate) generica può essere:
- out, può essere usato solo come tipo di ritorno.
- in, può essere usato come tipo per i parametri e nei vincoli
Esempi:
interface IEnumerator<out T> { bool MoveNext(); T Current {get;} } interface IComparer<in T> { int Compare(T left, T right); } delegate TResult Func<in TArg, out TResult> (Targ arg);
Non ci sono funzioni/variabili globali (al più membri statici)
Numero variabile di parametri: params T [] invece di T...
Gli array possono essere "jagged" per sempio:
int[][] myarray = new int[2][]; myarray[0]=new int[3]; myarray[0]=new int[9]; Ma ci sono anche gli array bidimensionali: int[,] myArray = new int[,]{1,2,3},{4,5,6}}
Recommended Comments
There are no comments to display.