Nell’articolo odierno verranno trattate alcune keyword utilizzate frequentemente.
Le classi con davanti la keyword static sono sostanzialmente delle classi che non possono essere istanziate. Oltre alle classi, ci è data la possibilità di dichiarare static anche i metodi e, visto che, nel momento in cui definiamo statico un metodo, lo definiamo in merito alla classe nella sua interezza senza necessitare della sua istanza, questo tipo di classi risultano molto utili per includere al loro interno algoritmi e funzionalità generiche, come succede ad esempio nel caso tipico delle classi di utilità.
Perciò, se abbiamo la necessità di scrivere un algoritmo e non sappiamo dove metterlo, e quest’algoritmo non richiede uno stato specifico dell’istanza di un oggetto, possiamo inserirlo direttamente in una classe statica.
Qui di seguito un esempio di come è possibile dichiarare un metodo statico interno ad una classe, per poi richiamarlo in seguito senza necessità di un’istanza, ma semplicemente richiamando la classe nella sua interezza:
Gli access modifiers sono sostanzialmente delle keywords che ci permettono di definire la visibilità di svariati elementi, come ad esempio: field, properties, classi, metodi etc.
Visto che uno dei concetti fondamentali, quando si programma, è quello di nascondere il più possibile, al fine di avere un codice robusto, i field e le properties ad utilizzatori esterni; se gestiamo bene la visibilità di alcune proprietà, è meno probabile che chi utilizza la classe in questione modifichi lo stato dell’istanza toccando valori sbagliati. Proprio per questo ci vengono incontro queste particolari keywords, le quali permettono di modificare i permessi di accesso ai valori:
Qui di seguito uno schema riassuntivo:
Un’altra keyword utilizzata frequentemente è la const. Com’è facilmente intuibile dal nome, questa keyword ci permette di dichiarare a codice delle costanti, le quali rimarranno immutate per tutta l’esecuzione del programma.
In questo esempio, vengono dichiarate delle costanti per i mesi, le settimane e i giorni. Essendo costanti, possono essere inizializzate in due punti: nel momento della dichiarazione, oppure all’interno del costruttore della classe.
Se nella stesura del codice ci accorgiamo che ci sono effettivamente dei valori che rimangono costanti, e che magari abbiamo definito come variabili, è caldamente consigliato dichiararli come const, perché così facendo abbiamo delle ottimizzazioni significative in termini di performance.
Se, invece di una variabile, dobbiamo definire delle classi o delle struct come costanti, non possiamo utilizzare la keyword const ma dobbiamo utilizzare per forza readonly.
Ogni volta che viene creata una classe o una struct, viene chiamato un costruttore. I costruttori consentono al programmatore di impostare dei valori predefiniti, limitare l’istanza e scrivere un codice flessibile e di facile lettura nel momento in cui viene istanziato un particolare oggetto.
In questo esempio stiamo definendo una classe Person con due properties: Nome (First) e Cognome (Last). Per queste properties vediamo che a livello di codice si sta esponendo solo il get, per cui queste due properties sono in sovra lettura e non possono essere modificate dopo essere state dichiarate. A questo punto risulta naturale chiedersi, essendo soltanto leggibili, quando ne viene inizializzato il valore.
Il valore viene inizializzato proprio tramite il costruttore, ovvero un metodo speciale che viene chiamato quando facciamo il new della classe in questione. Il costruttore è public, quindi chiunque può fare new di Person; ha il nome che coincide con il nome della classe ed ha dei parametri in ingresso che vengono utilizzati per inizializzare il nome ed il cognome.
Per cui, quando si inizializza una nuova istanza di Person, si potranno passare due valori (nome e cognome) che saranno usati per inizializzare questi due valori in sovra lettura. Questo pattern è abbastanza comune, per cui se ci sono tutta una serie di info fondamentali affinché l’istanza dell’oggetto abbia senso, tutte quelle info vanno inserite nel costruttore, in modo tale che nel momento in cui andremo a istanziare quella classe saremo obbligati a passare determinati valori per far sì che lo stato dell’istanza sia corretto.
In questo esempio, invece, possiamo notare come sia possibile avere più costruttori per una classe, richiamabili a seconda delle informazioni che disponiamo.
Il primo costruttore, prende in ingresso il salario annuale, il quale viene usato per inizializzare direttamente la property Salary, la quale ha public come visibilità.
Nel caso del secondo costruttore, invece, abbiamo due info da passare, le quali vengono moltiplicate tra di loro per ottenere il valore effettivo di Salary.
Quindi stiamo dicendo che: quando l’utilizzatore di Employee dovrà utilizzare questa classe, potrà inizializzare la classe in due modi diversi, a seconda delle info che possiede. Questa caratteristica, a livello di progettazione, è molto importante.
Nell’esempio della classe Manager, derivata da Employee, andiamo invece a ridefinire, appositamente per la classe Manager, il primo costruttore della classe Employee.
Diametralmente opposti ai costruttori, ci sono i finalizer o finalizzatori. Di fatto, il loro compito è quello di rimuovere risorse allocate dall’istanza. A livello di codice sii dichiara con la tilde, e possiamo sfruttarlo per compiere operazioni di pulizia della memoria. Il finalizer non viene chiamato dal programmatore ma viene chiamato automaticamente dal sistema quando viene avviato il servizio del garbage collector.
Difatti, nel momento in cui il garbage collector decide di togliere dalla memoria una delle variabili, va a chiamare il finalizer associato, per cui il codice definito nel finalizer verrà chiamato ed eseguito prima della rimozione di quella variabile dalla memoria.
Qui di seguito, la sua dichiarazione:
Questa keyword permette, sostanzialmente, di referenziare la classe di base, quella da cui ho derivato una classe.
In questo esempio, la classe Employee eredita dalla classe Person il metodo GetInfo(), il quale è stato dichiarato precedentemente come virtual dalla classe base. Visto che Employee esegue l’override di questo metodo, noi tramite la keyword base possiamo far riferimento, al posto del metodo sovrascritto da Employee, al metodo della classe Person, ovvero la classe di base da cui è stata derivata.
Keyword fondamentale, this fa riferimento all’istanza corrente della classe.
Possiamo notare nell’esempio che la classe Employee ha due property: alias e name. Abbiamo anche il costruttore, il quale ha due parametri in ingresso anche loro di nome alias e name.
Visto che i due parametri in ingresso al costruttore hanno gli stessi nomi dei field, come faccio a riferirmi ad uno piuttosto che all’altro? In questo caso, la keyword this risolve il problema. Visto che con essa mi riferisco all’istanza della classe: quando la uso, faccio riferimento ai field della classe; se invece non la metto, mi riferisco ai parametri in ingresso al costruttore.
La keyword is controlla che, data un’espressione, essa sia compatibile con un tipo particolare.
Immaginiamo di avere un metodo DoSomething(Object o) che prende in ingresso un oggetto: quando andiamo a definire un metodo che è parametrico rispetto ad un Object, stiamo sostanzialmente definendo un metodo che accetta in ingresso qualsiasi cosa. Essendo Object un oggetto generico, grazie ad is possiamo verificare se esso è effettivamente un’istanza di un certo tipo.
La keyword as permette di convertire esplicitamente il risultato di un’operazione in un tipo specifico.
Qui abbiamo un metodo Walk() con un Object generico in ingresso. Ciò che succede è che, appena entra nel metodo, la variabile p di tipo Person che ho definito va a controllare se effettivamente l’oggetto in ingresso è di tipo Person. Nel caso in cui non lo sia, p rimane null, altrimenti se è effettivamente un’istanza tipo Person si prosegue con l’esecuzione.
Il typeof è un operatore che ritorna un’istanza della classe Type, interna del C#, la quale contiene varie info che descrivono il tipo della nostra variabile. È sostanzialmente un modo più verboso per compiere le stesse cose che possiamo fare con as, solo che con typeof abbiamo più informazioni in merito alla variabile in questione, cosa che in certi casi può risultare molto utile.
La keyword var ci permette di dichiarare una variabile senza specificarne il tipo. Quindi, se dichiaro che un’ipotetica variabile num = 5, non dico esplicitamente che num è un intero ma sarà il compilatore, nel momento in cui vede l’inizializzazione, a capire che è un numero intero.
Per chi scrive il codice può essere una scorciatoia molto comoda, però, se ad esempio devo passare il codice in mano ad altri, questi ultimi potrebbero fare più fatica a capirne il tipo, motivo per cui se ne scoraggia l’ utilizzo a vantaggio di una tipizzazione corretta da codice.