I generici sono una funzionalità potente di C# che consente di scrivere codice riutilizzabile e flessibile. In questa guida esploreremo cos’è un generico, i suoi vantaggi e come utilizzarlo in C#. Se sei agli inizi, questo articolo ti aiuterà a comprendere i concetti base dei generici.
Cos’è un generico?
Un generico permette di definire classi, metodi, interfacce o delegati senza specificare in anticipo i tipi di dati con cui lavoreranno. In questo modo, puoi utilizzare un solo pezzo di codice per operare su diversi tipi, senza duplicazioni.
Vantaggi dei generici
I vantaggi principali dei generici includono:
- Riutilizzo del codice: consente di scrivere codice una sola volta e utilizzarlo per vari tipi di dati.
- Sicurezza del tipo: grazie ai generici, il tipo di dato è verificato a compile-time, riducendo la possibilità di errori.
- Prestazioni migliori: i generici eliminano la necessità di boxing/unboxing, migliorando così l’efficienza.
Sintassi di base dei generici
La sintassi dei generici in C# è semplice. Un generico viene dichiarato utilizzando una coppia di parentesi angolari (<>
), all’interno delle quali viene specificato il tipo “parametro”. Vediamo alcuni esempi.
Classi generiche
Una classe generica è una classe che può lavorare con qualsiasi tipo di dato. Ecco un esempio di come dichiarare una classe generica in C#:
public class Box
{
public T Value { get; set; }
public Box(T value)
{
Value = value;
}
}
In questo esempio, la classe Box
accetta un tipo di dato generico T
. Puoi creare un’istanza di Box
con qualsiasi tipo, ad esempio Box<int>
o Box<string>
.
Metodi generici
Un metodo generico può accettare parametri di tipo generico. Ecco un esempio:
public T Add(T a, T b)
{
return a; // Semplice esempio
}
In questo caso, il metodo Add
può lavorare con qualsiasi tipo di dato specificato durante l’invocazione.
Interfacce generiche
Le interfacce generiche funzionano in modo simile alle classi generiche. Puoi definire un’interfaccia che utilizza tipi generici:
public interface IRepository
{
void Add(T item);
T GetById(int id);
}
Vincoli nei generici
I vincoli nei generici permettono di limitare i tipi che possono essere utilizzati come parametri generici, rendendo il codice ancora più sicuro e specifico.
Esempio di vincolo con where
Puoi utilizzare il vincolo where
per specificare che il tipo generico deve implementare un’interfaccia o derivare da una classe specifica:
public class Repository where T : IEntity
{
// Implementazione
}
Altri vincoli comuni
- where T : struct – Il tipo generico deve essere un valore.
- where T : class – Il tipo generico deve essere una classe.
- where T : new() – Il tipo generico deve avere un costruttore senza parametri.
Generici e collezioni
Le collezioni generiche come List<T>
sono un esempio pratico di generici in C#. Ecco un esempio di utilizzo:
Esempio di lista generica
List numbers = new List();
numbers.Add(1);
numbers.Add(2);
In questo caso, List<int>
accetta solo elementi di tipo int
, garantendo così la sicurezza del tipo.
Best practices
Quando utilizzi i generici, ci sono alcune best practices che dovresti seguire per scrivere codice più efficiente e leggibile.
1. Utilizzare generici per migliorare la sicurezza del tipo
I generici ti permettono di evitare l’uso di tipi generici come object
, garantendo che solo il tipo corretto venga passato alle tue funzioni o classi.
2. Evitare il polimorfismo non necessario
Evita di utilizzare i generici per simulare il polimorfismo quando non necessario. I generici non dovrebbero essere una sostituzione del classico polimorfismo basato sull’ereditarietà.
3. Sfruttare i vincoli
Utilizza sempre i vincoli per limitare i tipi generici, assicurandoti che il tipo soddisfi le condizioni necessarie.
4. Documentare i vincoli
Assicurati di documentare correttamente i vincoli che imposti nei generici, in modo che il codice sia facilmente comprensibile per gli altri sviluppatori.