Универсальные классы и методы
Универсальные шаблоны представляют концепцию параметров типа в .NET. Универсальные шаблоны позволяют создавать классы и методы, откладывающие спецификацию одного или нескольких параметров типа, пока не будет использоваться класс или метод в коде. Как пример, ниже показан класс с параметром T
универсального типа. Этот класс может использоваться в другом клиентском коде, не требуя ресурсов и не создавая рисков, связанных с операциями приведения и упаковки-преобразования в среде выполнения.
// Declare the generic class.
public class GenericList<T>
{
public void Add(T input) { }
}
class TestGenericList
{
private class ExampleClass { }
static void Main()
{
// Declare a list of type int.
GenericList<int> list1 = new GenericList<int>();
list1.Add(1);
// Declare a list of type string.
GenericList<string> list2 = new GenericList<string>();
list2.Add("");
// Declare a list of type ExampleClass.
GenericList<ExampleClass> list3 = new GenericList<ExampleClass>();
list3.Add(new ExampleClass());
}
}
Универсальные классы и методы объединяют повторное использование, безопасность типов и эффективность таким образом, что их негенерические аналоги не могут. Параметры универсального типа заменяются аргументами типа во время компиляции. В предыдущем примере компилятор заменяет T
int
его. Универсальные типы наиболее часто используются с коллекциями и методами, которые выполняют с ними операции. Пространство имен System.Collections.Generic содержит несколько универсальных классов коллекций. Негенерические коллекции, такие как ArrayList не рекомендуется и поддерживаются только в целях совместимости. Дополнительные сведения см. в статье об универсальных шаблонах в .NET.
Вы также можете создать пользовательские универсальные типы и методы, чтобы предоставить собственные обобщенные решения и шаблоны проектирования, которые являются типобезопасными и эффективными. В следующем примере кода показан простой универсальный класс связанного списка для демонстрационных целей. (В большинстве случаев следует использовать класс, предоставленный List<T> .NET, вместо создания собственного.) Параметр T
типа используется в нескольких расположениях, где конкретный тип обычно используется для указания типа элемента, хранящегося в списке:
- в качестве типа параметра метода в методе
AddHead
; - в качестве типа возвращаемого значения свойства
Data
во вложенном классеNode
; - в качестве типа закрытого члена
data
во вложенном классе.
T
доступен для вложенного Node
класса. При GenericList<T>
создании экземпляра с конкретным типом, например как, GenericList<int>
каждое вхождение T
заменяется int
на .
// type parameter T in angle brackets
public class GenericList<T>
{
// The nested class is also generic on T.
private class Node
{
// T used in non-generic constructor.
public Node(T t)
{
next = null;
data = t;
}
private Node? next;
public Node? Next
{
get { return next; }
set { next = value; }
}
// T as private member data type.
private T data;
// T as return type of property.
public T Data
{
get { return data; }
set { data = value; }
}
}
private Node? head;
// constructor
public GenericList()
{
head = null;
}
// T as method parameter type:
public void AddHead(T t)
{
Node n = new Node(t);
n.Next = head;
head = n;
}
public IEnumerator<T> GetEnumerator()
{
Node? current = head;
while (current != null)
{
yield return current.Data;
current = current.Next;
}
}
}
В следующем примере кода показано, как клиентский код использует универсальный класс GenericList<T>
для создания списка целых чисел. При изменении аргумента типа следующий код создает списки строк или любого другого пользовательского типа:
class TestGenericList
{
static void Main()
{
// int is the type argument
GenericList<int> list = new GenericList<int>();
for (int x = 0; x < 10; x++)
{
list.AddHead(x);
}
foreach (int i in list)
{
System.Console.Write(i + " ");
}
System.Console.WriteLine("\nDone");
}
}
Примечание.
Универсальные типы не ограничиваются классами. В предыдущих примерах используются class
типы, но можно определить универсальные interface
и struct
типы, включая record
типы.
Общие сведения об универсальных шаблонах
- Используйте универсальные типы, чтобы получить максимально широкие возможности многократного использования кода, обеспечения безопасности типов и повышения производительности.
- Чаще всего универсальные шаблоны используются для создания классов коллекций.
- Библиотека классов .NET содержит несколько универсальных классов коллекций в пространстве имен System.Collections.Generic. Универсальные коллекции следует использовать всякий раз, когда это возможно, вместо классов, таких как ArrayList в System.Collections пространстве имен.
- Вы можете создавать собственные универсальные интерфейсы, классы, методы, события и делегаты.
- Универсальные классы можно ограничить, чтобы обеспечить доступ к методам для определенных типов данных.
- Вы можете получить сведения во время выполнения о типах, используемых в универсальном типе данных, с помощью отражения.
Спецификация языка C#
Дополнительные сведения см. в спецификации языка C#.