English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Una generica è una forma generale, non una forma specifica. In C#, una generica significa non specifica per un tipo di dati specifico.
C# ti permette di usare i parametri di tipo senza specificare un tipo di dati specifico per definire classi generiche, interfacce, classi astratte, campi, metodi, metodi statici, proprietà, eventi, deleghe e operatori. I parametri di tipo sono segnaposto per tipi specifici specificati durante la creazione dell'istanza di un tipo generico.
Si può dichiarare una generica specificando il parametro di tipo nei angoli acuti dopo il nome del tipo, ad esempio TypeName<T>, dove T è il parametro di tipo.
Le classi generiche sono definite utilizzando parametri di tipo nei angoli acuti dopo il nome della classe. Di seguito è definita una classe generica.
class DataStore<T> { public T Data { get; set; } }
Sopra, DataStore è una classe generica. T è chiamato parametro di tipo e può essere utilizzato come campo, proprietà, parametro del metodo, tipo di ritorno e tipo di delega nella classe DataStore. Ad esempio, Data è una proprietà generica perché abbiamo utilizzato il parametro di tipo T come suo tipo, non un tipo di dati specifico.
Puoi anche definire più parametri di tipo e separarli con virgole.
class KeyValuePair<TKey, TValue> { public TKey Key { get; set; } public TValue Value { get; set; } }
Puoi creare un'istanza di classe generica specificando il tipo effettivo nei angoli acuti. Di seguito, viene creata un'istanza di classe generica DataStore.
DataStore<string> store = new DataStore<string>();
Sopra, abbiamo specificato il tipo all'interno degli angoli acuti durante la creazione dell'istanza. Pertanto, T verrà sostituito con qualsiasi tipo T utilizzato nell'intera classe durante la compilazione. Di conseguenza, il tipo dell'attributo Data è string.
下图说明了泛型的工作方式。
您可以为Data属性分配一个字符串值。尝试分配除字符串以外的其他值将导致编译时错误。
DataStore<string> store = new DataStore<string>(); store.Data = "Hello World!"; // obj.Data = 123; //编译时错误
您可以为不同的对象指定不同的数据类型,如下所示。
DataStore<string> strStore = new DataStore<string>(); strStore.Data = "Hello World!"; //strStore.Data = 123; // 编译时错误 DataStore<int> intStore = new DataStore<int>(); intStore.Data = 100; //intStore.Data = "Hello World!"; // 编译时错误 KeyValuePair<int, string> kvp1 = new KeyValuePair<int, string>(); kvp1.Key = 100; kvp1.Value = "Hundred"; KeyValuePair<string, string> kvp2 = new KeyValuePair<string, string>(); kvp2.Key = "IT"; kvp2.Value = "Information Technology";
泛型类增加了可重用性。类型越多,可重用性就越高。然而,过多的泛化会使代码难以理解和维护。
泛型类可以是其他泛型或非泛型类或抽象类的基类。
泛型类可以派生自其他泛型或非泛型接口,类或抽象类。
泛型类可以包含泛型字段。但是,无法初始化。
class DataStore<T> { public T data; }
下面声明一个泛型数组。
class DataStore<T> { public T[] data = new T[10]; }
使用类型参数声明其返回类型或参数的方法称为泛型方法。
class DataStore<T> { private T[] _data = new T[10]; public void AddOrUpdate(int index, T item) { if(index >= 0 && index < 10) _data[index] = item; } public T GetData(int index) { if(index >= 0 && index < 10) return _data[index]; else return default(T); } }
I metodi AddorUpdate() e GetData() sono metodi generici. Il tipo effettivo del parametro item viene specificato durante l'istanziazione della classe DataStore<T>, come nel seguente esempio.
DataStore<string> cities = new DataStore<string>(); cities.AddOrUpdate(0, "Mumbai"); cities.AddOrUpdate(1, "Chicago"); cities.AddOrUpdate(2, "London"); DataStore<int> empIds = new DataStore<int>(); empIds.AddOrUpdate(0, 50); empIds.AddOrUpdate(1, 65); empIds.AddOrUpdate(2, 89);
I parametri di tipo generici possono essere utilizzati insieme a più parametri con o senza parametri non generici e tipo di ritorno. Ecco degli esempi validi di sovraccarico di metodi generici.
public void AddOrUpdate(int index, T data) { } public void AddOrUpdate(T data1, T data2) { } public void AddOrUpdate<U>(T data1, U data2) { } public void AddOrUpdate(T data) { }
Utilizzando il nome del metodo tra parentesi angolari per specificare il tipo di parametro, una classe non generica può contenere metodi generici, come nel seguente esempio.
class Printer { public void Print<T>(T data) { Console.WriteLine(data); } } Printer printer = new Printer(); printer.Print<int>(100); printer.Print(200); // Inferito il valore specificato printer.Print<string>("Hello"); printer.Print("World!"); // Inferito il valore specificato
I generici migliorano la riutilizzabilità del codice. Non è necessario scrivere codice per gestire diversi tipi di dati.
I generici sono sicuri per il tipo. Se si tenta di utilizzare un tipo di dati diverso da quello specificato nella definizione, si verificherà un errore durante la compilazione.
I generici hanno un vantaggio prestazionale perché eliminano la possibilità di boxing e unboxing.