Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Дженерики позволяют адаптировать метод, класс, структуру или интерфейс к конкретному типу данных, который они обрабатывают. Например, вместо использования Hashtable класса, позволяющего использовать ключи и значения любого типа, можно использовать Dictionary<TKey,TValue> универсальный класс и указать типы, разрешенные для ключа и значения. Среди преимуществ дженериков — повышенная возможность повторного использования кода и обеспечение безопасности типов.
Определение и использование универсальных шаблонов
Обобщения — это классы, структуры, интерфейсы и методы с заполнителями (параметрами типа) для одного или нескольких типов, которые они хранят или используют. Универсальный класс коллекции может использовать параметр типа в качестве заполнителя для типа объектов, которые он хранит. Параметры типа отображаются как типы полей и типы параметров методов. Универсальный метод может использовать параметр типа в качестве типа возвращаемого значения или в качестве типа одного из его формальных параметров.
Следующий код иллюстрирует простое определение универсального класса.
public class SimpleGenericClass<T>
{
public T Field;
}
Public Class SimpleGenericClass(Of T)
Public Field As T
End Class
При создании экземпляра универсального класса можно указать фактические типы, которые следует заменить параметрами типа. Это устанавливает новый универсальный класс, называемый созданным универсальным классом, при этом выбранные типы заменяются везде, где отображаются параметры типа. Результатом является типобезопасный класс, который адаптирован к выбору типов, как показано в следующем коде.
public static void Main()
{
SimpleGenericClass<string> g = new SimpleGenericClass<string>();
g.Field = "A string";
//...
Console.WriteLine($"SimpleGenericClass.Field = \"{g.Field}\"");
Console.WriteLine($"SimpleGenericClass.Field.GetType() = {g.Field.GetType().FullName}");
}
Public Shared Sub Main()
Dim g As New SimpleGenericClass(Of String)
g.Field = "A string"
'...
Console.WriteLine("SimpleGenericClass.Field = ""{0}""", g.Field)
Console.WriteLine("SimpleGenericClass.Field.GetType() = {0}", g.Field.GetType().FullName)
End Sub
Терминология
Для обсуждения универсальных шаблонов в .NET используются следующие термины:
Определение универсального типа — это объявление класса, структуры или интерфейса, которое работает в качестве шаблона, с заполнителями для типов, которые он может содержать или использовать. Например, System.Collections.Generic.Dictionary<TKey,TValue> класс может содержать два типа: ключи и значения. Так как определение универсального типа является только шаблоном, нельзя создавать экземпляры класса, структуры или интерфейса, который является определением универсального типа.
Параметры универсального типа или параметры типа — это заполнители в определении универсального типа или метода. Универсальный тип System.Collections.Generic.Dictionary<TKey,TValue> имеет два параметра типа:
TKey
иTValue
, которые представляют типы его ключей и значений.Созданный универсальный тип или созданный тип является результатом указания типов для параметров универсального типа определения универсального типа.
Аргумент универсального типа — это любой тип, заменяющийся параметром универсального типа.
Общий термин обобщенных типов включает как построенные типы, так и обобщенные определения типов.
Ковариантность и контравариантность параметров универсального типа позволяют использовать созданные универсальные типы, аргументы типа которых являются более производными (ковариантностью) или менее производными (контравариантностью), чем целевой сконструированный тип. Ковариантность и контравариантность коллективно называются вариантностью. Дополнительные сведения см. в статье о ковариации и контравариации.
Ограничения — это ограничения, установленные для параметров универсального типа. Например, можно ограничить параметр типа типами, реализующими System.Collections.Generic.IComparer<T> универсальный интерфейс, чтобы обеспечить упорядочение экземпляров типа. Параметры типа также можно ограничить типами, имеющими определенный базовый класс, с конструктором без параметров или ссылочными типами или типами значений. Пользователи универсального типа не могут заменить аргументы типа, которые не удовлетворяют ограничениям.
Определение универсального метода — это метод с двумя списками параметров: список параметров универсального типа и список формальных параметров. Параметры типа могут отображаться как возвращаемый тип или как типы формальных параметров, как показано в следующем коде.
T MyGenericMethod<T>(T arg) { T temp = arg; //... return temp; }
Function MyGenericMethod(Of T)(ByVal arg As T) As T Dim temp As T = arg '... Return temp End Function
Универсальные методы могут отображаться в универсальных или негенерических типах. Важно отметить, что метод не является универсальным, так как он принадлежит универсальному типу, или даже потому, что он имеет формальные параметры, типы которых являются универсальными параметрами включающего типа. Метод является универсальным, только если он имеет собственный список параметров типа. В следующем коде единственный метод
G
является универсальным.class A { T G<T>(T arg) { T temp = arg; //... return temp; } } class MyGenericClass<T> { T M(T arg) { T temp = arg; //... return temp; } }
Class A Function G(Of T)(ByVal arg As T) As T Dim temp As T = arg '... Return temp End Function End Class Class MyGenericClass(Of T) Function M(ByVal arg As T) As T Dim temp As T = arg '... Return temp End Function End Class
Преимущества и недостатки универсальных шаблонов
Существует множество преимуществ использования универсальных коллекций и делегатов:
Безопасность типов. Обобщения переносят бремя обеспечения безопасности типов с вас на компилятор. Для проверки правильного типа данных не требуется писать код, так как он применяется во время компиляции. Необходимость приведения типов и возможность ошибок во время выполнения уменьшаются.
Меньше кода и его проще повторно использовать. Нет необходимости наследовать от базового типа и переопределять члены. Например, LinkedList<T> готово к немедленному использованию. Например, можно создать связанный список строк со следующим объявлением переменной:
LinkedList<string> llist = new LinkedList<string>();
Dim llist As New LinkedList(Of String)()
Улучшенная производительность. Универсальные типы коллекций обычно показывают лучшую производительность при хранении и обработке типов значений, поскольку нет необходимости в упаковке этих типов.
Универсальные делегаты позволяют выполнять типобезопасные обратные вызовы без необходимости создавать несколько классов делегатов. Например, Predicate<T> универсальный делегат позволяет создать метод, реализующий собственные критерии поиска для определенного типа, и использовать метод с методами Array такого типа, как Find, FindLastи FindAll.
Универсальные шаблоны упрощают динамически созданный код. При использовании универсальных шаблонов с динамически созданным кодом не нужно создавать тип. Это увеличивает количество сценариев, в которых можно использовать упрощенные динамические методы вместо создания целых сборок. Дополнительные сведения см. в разделе "Практическое руководство. Определение и выполнение динамических методов " и DynamicMethod.
Ниже приведены некоторые ограничения универсальных шаблонов:
Универсальные типы могут быть производными от большинства базовых классов, таких как MarshalByRefObject (и ограничения могут использоваться для того, чтобы требовать, чтобы параметры универсального типа были производными от базовых классов, таких как MarshalByRefObject). Однако .NET не поддерживает универсальные типы, привязанные к контексту. Универсальный тип может быть производным от ContextBoundObject, но при попытке создать экземпляр этого типа вызывается TypeLoadException.
Перечисления не могут иметь параметры универсального типа. Перечисление может быть универсальным только случайно (например, так как оно вложено в универсальный тип, определяемый с помощью Visual Basic, C#или C++). Дополнительные сведения см. в разделе "Перечисления" в системе общего типа.
Упрощенные динамические методы не могут быть универсальными.
В Visual Basic, C#и C++вложенный тип, заключенный в универсальный тип, нельзя создать экземпляр, если только типы не были назначены параметрам типа всех вложенных типов. Другой способ сказать это заключается в том, что в отражении вложенный тип, определенный с помощью этих языков, включает параметры типа всех его вложенных типов. Это позволяет использовать параметры типа вложенных типов в определениях членов вложенного типа. Дополнительные сведения см. в MakeGenericTypeразделе "Вложенные типы".
Примечание.
Вложенный тип, который определяется путем создания кода в динамической сборке или с помощью Ilasm.exe (сборщик IL) не требуется для включения параметров типа его вложенных типов; Однако если он не включает их, параметры типа не находятся в области вложенном классе.
Дополнительные сведения см. в MakeGenericTypeразделе "Вложенные типы".
Поддержка библиотеки классов и языков
.NET предоставляет ряд универсальных классов коллекций в следующих пространствах имен:
Пространство System.Collections.Generic имен содержит большинство универсальных типов коллекций, предоставляемых .NET, таких как и Dictionary<TKey,TValue> универсальные List<T> классы.
Пространство имен System.Collections.ObjectModel содержит дополнительные универсальные типы коллекций, такие как универсальный класс ReadOnlyCollection<T>, которые полезны для предоставления объектных моделей пользователям ваших классов.
Универсальные интерфейсы для реализации сравнения сортировки и равенства предоставляются в System пространстве имен, а также универсальные типы делегатов для обработчиков событий, преобразований и предикатов поиска.
Пространство System.Numerics имен предоставляет универсальные интерфейсы для математических функций (доступных в .NET 7 и более поздних версиях). Дополнительные сведения см. в разделе "Универсальная математика".
Поддержка универсальных типов и универсальных методов была добавлена в пространство имен System.Reflection для исследования универсальных типов и методов, в System.Reflection.Emit для создания динамических сборок, содержащих универсальные типы и методы, и в System.CodeDom для генерации исходных графов, включающих универсальные элементы.
Общая языковая среда выполнения (CLR) предоставляет новые коды операций и префиксы для поддержки универсальных типов в общем промежуточном языке (CIL), включая Stelem, Ldelem, Unbox_Any, Constrained и Readonly.
Visual C++, C# и Visual Basic обеспечивают полную поддержку определения и использования универсальных шаблонов. Подробнее о поддержке языка можно узнать в разделе "Универсальные типы" в Visual Basic, "Введение в универсальные шаблоны" и разделе "Обзор универсальных шаблонов" в Visual C++.
Вложенные типы и универсальные типы
Тип, вложенный в универсальный тип, может зависеть от параметров типа включаемого универсального типа. Общая среда выполнения (CLR) считает вложенные типы обобщенными, даже если у них нет собственных параметров обобщенного типа. При создании экземпляра вложенного типа необходимо указать аргументы типа для всех окружающих обобщенных типов.
Связанные статьи
Заголовок | Описание |
---|---|
Универсальные коллекции в .NET | Описывает универсальные классы коллекций и другие универсальные типы в .NET. |
Универсальные делегаты для управления массивами и списками | Описание универсальных делегатов для преобразований, предикатов поиска и действий, выполняемых для элементов массива или коллекции. |
Универсальная математика | Описывает, как можно выполнять математические операции в универсальном формате. |
Универсальные интерфейсы | Описывает универсальные интерфейсы, предоставляющие общие функциональные возможности в семействах универсальных типов. |
ковариантность и контравариантность | Описывает ковариацию и контравариантность в параметрах универсального типа. |
Часто используемые типы коллекций | Содержит сводную информацию о характеристиках и сценариях использования типов коллекций в .NET, включая универсальные типы. |
Когда следует использовать универсальные коллекции | Описывает общие правила определения того, когда следует использовать универсальные типы коллекций. |
#B0 Как определить универсальный тип с использованием Reflection Emit #C1 | Объясняет, как создавать динамические сборки, включающие универсальные типы и методы. |
Универсальные типы в Visual Basic | Описание универсальной функции для пользователей Visual Basic, включая инструкции по использованию и определению универсальных типов. |
Введение в обобщения | Общие сведения об определении и использовании универсальных типов для пользователей C#. |
Обзор универсальных шаблонов в Visual C++ | Описывает универсальные функции для пользователей C++, включая различия между универсальными и шаблонами. |