Type.MakeGenericType(Type[]) Метод
Определение
Важно!
Некоторые сведения относятся к предварительной версии продукта, в которую до выпуска могут быть внесены существенные изменения. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
Заменяет элементы массива типов для параметров типа текущего определения универсального типа и возвращает Type объект, представляющий результирующий созданный тип.
public:
abstract Type ^ MakeGenericType(... cli::array <Type ^> ^ typeArguments);
public:
virtual Type ^ MakeGenericType(... cli::array <Type ^> ^ typeArguments);
public abstract Type MakeGenericType(params Type[] typeArguments);
[System.Diagnostics.CodeAnalysis.RequiresDynamicCode("The native code for this instantiation might not be available at runtime.")]
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")]
public virtual Type MakeGenericType(params Type[] typeArguments);
public virtual Type MakeGenericType(params Type[] typeArguments);
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")]
public virtual Type MakeGenericType(params Type[] typeArguments);
abstract member MakeGenericType : Type[] -> Type
[<System.Diagnostics.CodeAnalysis.RequiresDynamicCode("The native code for this instantiation might not be available at runtime.")>]
[<System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")>]
abstract member MakeGenericType : Type[] -> Type
override this.MakeGenericType : Type[] -> Type
abstract member MakeGenericType : Type[] -> Type
override this.MakeGenericType : Type[] -> Type
[<System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")>]
abstract member MakeGenericType : Type[] -> Type
override this.MakeGenericType : Type[] -> Type
Public MustOverride Function MakeGenericType (ParamArray typeArguments As Type()) As Type
Public Overridable Function MakeGenericType (ParamArray typeArguments As Type()) As Type
Параметры
- typeArguments
- Type[]
Массив типов, заменяемых параметрами типа текущего универсального типа.
Возвращаемое значение
Представляет Type созданный тип, сформированный путем замены элементов typeArguments для параметров типа текущего универсального типа.
- Атрибуты
Исключения
Текущий тип не представляет определение универсального типа. То есть IsGenericTypeDefinition возвращается false.
Число элементов typeArguments не совпадает с числом параметров типа в текущем определении универсального типа.
–или–
Любой элемент typeArguments не удовлетворяет ограничениям, указанным для соответствующего параметра типа текущего универсального типа.
–или–
typeArgumentsсодержит элемент, который является типом указателя (возвращается), типом по ссылкам (IsPointertrueвозвращаетсяIsByReftrue) или Void.
Вызываемый метод не поддерживается в базовом классе. Производные классы должны предоставлять реализацию.
Примеры
В следующем примере метод используется MakeGenericType для создания созданного типа из определения универсального типа для Dictionary<TKey,TValue> типа. Созданный тип представляет Dictionary<TKey,TValue>Test объекты со строковыми ключами.
using System;
using System.Reflection;
using System.Collections.Generic;
public class Test
{
public static void Main()
{
Console.WriteLine("\r\n--- Create a constructed type from the generic Dictionary type.");
// Create a type object representing the generic Dictionary
// type, by omitting the type arguments (but keeping the
// comma that separates them, so the compiler can infer the
// number of type parameters).
Type generic = typeof(Dictionary<,>);
DisplayTypeInfo(generic);
// Create an array of types to substitute for the type
// parameters of Dictionary. The key is of type string, and
// the type to be contained in the Dictionary is Test.
Type[] typeArgs = { typeof(string), typeof(Test) };
// Create a Type object representing the constructed generic
// type.
Type constructed = generic.MakeGenericType(typeArgs);
DisplayTypeInfo(constructed);
// Compare the type objects obtained above to type objects
// obtained using typeof() and GetGenericTypeDefinition().
Console.WriteLine("\r\n--- Compare types obtained by different methods:");
Type t = typeof(Dictionary<String, Test>);
Console.WriteLine("\tAre the constructed types equal? {0}", t == constructed);
Console.WriteLine("\tAre the generic types equal? {0}",
t.GetGenericTypeDefinition() == generic);
}
private static void DisplayTypeInfo(Type t)
{
Console.WriteLine("\r\n{0}", t);
Console.WriteLine("\tIs this a generic type definition? {0}",
t.IsGenericTypeDefinition);
Console.WriteLine("\tIs it a generic type? {0}",
t.IsGenericType);
Type[] typeArguments = t.GetGenericArguments();
Console.WriteLine("\tList type arguments ({0}):", typeArguments.Length);
foreach (Type tParam in typeArguments)
{
Console.WriteLine("\t\t{0}", tParam);
}
}
}
/* This example produces the following output:
--- Create a constructed type from the generic Dictionary type.
System.Collections.Generic.Dictionary`2[TKey,TValue]
Is this a generic type definition? True
Is it a generic type? True
List type arguments (2):
TKey
TValue
System.Collections.Generic.Dictionary`2[System.String, Test]
Is this a generic type definition? False
Is it a generic type? True
List type arguments (2):
System.String
Test
--- Compare types obtained by different methods:
Are the constructed types equal? True
Are the generic types equal? True
*/
open System
open System.Collections.Generic
type Test() = class end
let displayTypeInfo (t: Type) =
printfn $"\r\n{t}"
printfn $"\tIs this a generic type definition? {t.IsGenericTypeDefinition}"
printfn $"\tIs it a generic type? {t.IsGenericType}"
let typeArguments = t.GetGenericArguments()
printfn $"\tList type arguments ({typeArguments.Length}):"
for tParam in typeArguments do
printfn $"\t\t{tParam}"
printfn "\r\n--- Create a constructed type from the generic Dictionary type."
// Create a type object representing the generic Dictionary
// type, by calling .GetGenericTypeDefinition().
let generic = typeof<Dictionary<_,_>>.GetGenericTypeDefinition()
displayTypeInfo generic
// Create an array of types to substitute for the type
// parameters of Dictionary. The key is of type string, and
// the type to be contained in the Dictionary is Test.
let typeArgs = [| typeof<string>; typeof<Test> |]
// Create a Type object representing the constructed generic type.
let constructed = generic.MakeGenericType typeArgs
displayTypeInfo constructed
(* This example produces the following output:
--- Create a constructed type from the generic Dictionary type.
System.Collections.Generic.Dictionary`2[TKey,TValue]
Is this a generic type definition? True
Is it a generic type? True
List type arguments (2):
TKey
TValue
System.Collections.Generic.Dictionary`2[System.String, Test]
Is this a generic type definition? False
Is it a generic type? True
List type arguments (2):
System.String
Test
*)
Public Class Test
Public Shared Sub Main2()
Console.WriteLine(vbCrLf & "--- Create a constructed type from the generic Dictionary type.")
' Create a type object representing the generic Dictionary
' type, by omitting the type arguments (but keeping the
' comma that separates them, so the compiler can infer the
' number of type parameters).
Dim generic As Type = GetType(Dictionary(Of ,))
DisplayTypeInfo(generic)
' Create an array of types to substitute for the type
' parameters of Dictionary. The key is of type string, and
' the type to be contained in the Dictionary is Test.
Dim typeArgs() As Type = {GetType(String), GetType(Test)}
' Create a Type object representing the constructed generic
' type.
Dim constructed As Type = generic.MakeGenericType(typeArgs)
DisplayTypeInfo(constructed)
' Compare the type objects obtained above to type objects
' obtained using GetType() and GetGenericTypeDefinition().
Console.WriteLine(vbCrLf & "--- Compare types obtained by different methods:")
Dim t As Type = GetType(Dictionary(Of String, Test))
Console.WriteLine(vbTab & "Are the constructed types equal? " _
& (t Is constructed))
Console.WriteLine(vbTab & "Are the generic types equal? " _
& (t.GetGenericTypeDefinition() Is generic))
End Sub
Private Shared Sub DisplayTypeInfo(ByVal t As Type)
Console.WriteLine(vbCrLf & t.ToString())
Console.WriteLine(vbTab & "Is this a generic type definition? " _
& t.IsGenericTypeDefinition)
Console.WriteLine(vbTab & "Is it a generic type? " _
& t.IsGenericType)
Dim typeArguments() As Type = t.GetGenericArguments()
Console.WriteLine(vbTab & "List type arguments ({0}):", _
typeArguments.Length)
For Each tParam As Type In typeArguments
Console.WriteLine(vbTab & vbTab & tParam.ToString())
Next
End Sub
End Class
' This example produces the following output:
'
'--- Create a constructed type from the generic Dictionary type.
'
'System.Collections.Generic.Dictionary'2[TKey,TValue]
' Is this a generic type definition? True
' Is it a generic type? True
' List type arguments (2):
' TKey
' TValue
'
'System.Collections.Generic.Dictionary`2[System.String,Test]
' Is this a generic type definition? False
' Is it a generic type? True
' List type arguments (2):
' System.String
' Test
'
'--- Compare types obtained by different methods:
' Are the constructed types equal? True
' Are the generic types equal? True
Комментарии
Этот MakeGenericType метод позволяет писать код, который назначает определенные типы параметрам типа определения универсального типа, создавая таким образом Type объект, представляющий конкретный созданный тип. Этот Type объект можно использовать для создания экземпляров среды выполнения созданного типа.
Типы, созданные с MakeGenericType, могут быть открытыми, то есть некоторые из их аргументов типа могут быть параметрами типа для окружающих универсальных методов или типов. При отправке динамических сборок можно использовать такие открытые созданные типы. Например, рассмотрим классы Base и Derived в следующем коде.
public class Base<T, U> { }
public class Derived<V> : Base<int, V> { }
type Base<'T, 'U>() = class end
type Derived<'V>() = inherit Base<int, 'V>()
Public Class Base(Of T, U)
End Class
Public Class Derived(Of V)
Inherits Base(Of Integer, V)
End Class
Чтобы сгенерировать Derived в динамической сборке, необходимо создать базовый тип. Для этого вызовите метод MakeGenericType у объекта Type, который представляет класс Base, с использованием универсальных аргументов типа Int32 и параметра типа V из Derived. Так как типы и параметры универсального типа представлены Type объектами, массив, содержащий оба типа, можно передать в MakeGenericType метод.
Замечание
Конструированный тип, такой как Base<int, V>, полезен при создании кода, но вы не можете вызвать метод MakeGenericType для этого типа, потому что Base<int, V> это не определение универсального типа. Чтобы создать закрытый сконструированный тип, который может быть создан, сначала вызовите метод GetGenericTypeDefinition для получения объекта Type, представляющего определение обобщённого типа, а затем вызовите MakeGenericType с требуемыми аргументами типа.
Объект Type, возвращаемый MakeGenericType, идентичен тому объекту, который получается путем вызова метода Type результирующего созданного типа или метода GetType любого созданного типа, который был создан из того же определения универсального типа с использованием тех же типов аргументов.
Замечание
Массив универсальных типов не является универсальным типом. Невозможно вызвать MakeGenericType для типа массива, такого как C<T>[] (Dim ac() As C(Of T) в Visual Basic). Чтобы построить закрытый универсальный тип из C<T>[], выполните вызов GetElementType, чтобы получить определение универсального типа C<T>; выполните вызов MakeGenericType на определение универсального типа, чтобы создать сконструированный тип; и, наконец, вызовите метод MakeArrayType на сконструированном типе, чтобы создать тип массива. То же самое относится к типам указателей и ref типам (ByRef в Visual Basic).
Список инвариантных условий терминов, используемых в универсальном отражении, см. в IsGenericType примечаниях свойств.
Вложенные типы
Если универсальный тип определен с помощью C#, C++или Visual Basic, вложенные типы являются универсальными. Это верно, даже если вложенные типы не имеют собственных параметров типа, так как все три языка включают параметры типа в списки параметров типа вложенных типов. Рассмотрим следующие классы:
public class Outermost<T>
{
public class Inner<U>
{
public class Innermost1<V> {}
public class Innermost2 {}
}
}
Public Class Outermost(Of T)
Public Class Inner(Of U)
Public Class Innermost1(Of V)
End Class
Public Class Innermost2
End Class
End Class
End Class
Список параметров типа вложенного класса Inner имеет два параметра типа, T и Uпервый из которых является параметром типа его заключенного класса. Аналогичным образом, список параметров типа вложенного класса Innermost1 имеет три параметра типа: T, U и V, причем T и U поступают из его обрамляющих классов. Вложенный класс Innermost2 имеет два параметра типа T и U, которые приходят из его внешних классов.
Если список параметров включаемого типа имеет несколько параметров типа, все параметры типа в порядке включаются в список параметров типа вложенного типа.
Чтобы создать универсальный тип из определения универсального типа для вложенного типа, вызовите MakeGenericType метод с массивом, сформированным путем объединения массивов аргументов типа всех вложенных типов, начиная с самого внешнего универсального типа и заканчивая массивом аргументов типа вложенного типа, если он имеет собственные параметры типа. Чтобы создать экземпляр Innermost1, вызовите MakeGenericType метод с массивом, содержащим три типа, для назначения T, U и V. Чтобы создать экземпляр Innermost2, вызовите MakeGenericType метод с массивом, содержащим два типа, для назначения T и U.
Языки распространяют параметры типа обрамляющих типов таким образом, чтобы можно было использовать параметры типа обрамляющих типов для определения полей вложенных типов. В противном случае параметры типа не будут находиться в пределах области видимости тел вложенных типов. Можно определить вложенные типы без передачи параметров типа внешних типов, создавая код в динамических сборках или используя Ilasm.exe (сборщик IL). Рассмотрим следующий код для сборщика CIL:
.class public Outer<T> {
.class nested public Inner<U> {
.class nested public Innermost {
}
}
}
В этом примере невозможно определить поле типа T или U в классе Innermost, так как эти параметры типа не находятся в области видимости. Следующий код сборщика определяет вложенные классы, которые ведут себя так, как они будут определяться в C++, Visual Basic и C#:
.class public Outer<T> {
.class nested public Inner<T, U> {
.class nested public Innermost<T, U, V> {
}
}
}
Вы можете использовать Ildasm.exe (IL Disassembler) для изучения вложенных классов, определенных на высокоуровневых языках, и наблюдать за этой схемой именования.