Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Information om generiska typer erhålls på samma sätt som information om andra typer: genom att undersöka ett Type objekt som representerar den generiska typen. Huvudskillnaden är att en allmän typ har en lista över Type objekt som representerar dess generiska typparametrar. Den första proceduren i det här avsnittet undersöker generiska typer.
Du kan skapa ett Type-objekt som representerar en konstruerad typ genom att binda typargument till typparametrarna för en generisk typdefinition. Det andra förfarandet visar detta.
Så här undersöker du en allmän typ och dess typparametrar
Hämta en instans av Type som representerar den generiska typen. I följande kod hämtas typen med hjälp av operatorn C#
typeof
(GetType
i Visual Basic). Andra sätt att hämta ett Type-objekt finns i Type. I resten av den här proceduren finns typen i en metodparameter med namnett
.Type d1 = typeof(Dictionary<,>);
Dim d1 As Type = GetType(Dictionary(Of ,))
Använd egenskapen IsGenericType för att avgöra om typen är generisk och använd egenskapen IsGenericTypeDefinition för att avgöra om typen är en allmän typdefinition.
Console.WriteLine($" Is this a generic type? {t.IsGenericType}"); Console.WriteLine($" Is this a generic type definition? {t.IsGenericTypeDefinition}");
Console.WriteLine(" Is this a generic type? " _ & t.IsGenericType) Console.WriteLine(" Is this a generic type definition? " _ & t.IsGenericTypeDefinition)
Hämta en matris som innehåller argument av allmän typ med hjälp av metoden GetGenericArguments.
Type[] typeParameters = t.GetGenericArguments();
Dim typeParameters() As Type = t.GetGenericArguments()
För varje typargument avgör du om det är en typparameter (till exempel i en allmän typdefinition) eller en typ som har angetts för en typparameter (till exempel i en konstruerad typ) med egenskapen IsGenericParameter.
Console.WriteLine($" List {typeParameters.Length} type arguments:"); foreach (Type tParam in typeParameters) { if (tParam.IsGenericParameter) { DisplayGenericParameter(tParam); } else { Console.WriteLine($" Type argument: {tParam}"); } }
Console.WriteLine(" List {0} type arguments:", _ typeParameters.Length) For Each tParam As Type In typeParameters If tParam.IsGenericParameter Then DisplayGenericParameter(tParam) Else Console.WriteLine(" Type argument: {0}", _ tParam) End If Next
I typsystemet representeras en generisk typparameter av en instans av Type, precis som vanliga typer är. Följande kod visar namnet och parameterpositionen för ett Type objekt som representerar en allmän typparameter. Parameterns position är en trivial upplysning här; det är av större intresse när du undersöker en typparameter som har använts som ett typargument för en annan generisk typ.
Console.WriteLine($" Type parameter: {tp.Name} position {tp.GenericParameterPosition}");
Private Shared Sub DisplayGenericParameter(ByVal tp As Type) Console.WriteLine(" Type parameter: {0} position {1}", _ tp.Name, tp.GenericParameterPosition)
Fastställa grundtypsbegränsningen och gränssnittsbegränsningarna för en generisk typparameter med hjälp av metoden GetGenericParameterConstraints för att hämta alla begränsningar i en enda matris. Begränsningar är inte garanterade att vara i någon viss ordning.
foreach (Type iConstraint in tp.GetGenericParameterConstraints()) { if (iConstraint.IsInterface) { Console.WriteLine($" Interface constraint: {iConstraint}"); } } Console.WriteLine($" Base type constraint: {tp.BaseType ?? tp.BaseType: None}");
Dim classConstraint As Type = Nothing For Each iConstraint As Type In tp.GetGenericParameterConstraints() If iConstraint.IsInterface Then Console.WriteLine(" Interface constraint: {0}", _ iConstraint) End If Next If classConstraint IsNot Nothing Then Console.WriteLine(" Base type constraint: {0}", _ tp.BaseType) Else Console.WriteLine(" Base type constraint: None") End If
Använd egenskapen GenericParameterAttributes för att identifiera de särskilda begränsningarna för en typparameter, till exempel att kräva att den är en referenstyp. Egenskapen innehåller också värden som representerar variansen, som du kan maskera som du ser i följande kod.
GenericParameterAttributes sConstraints = tp.GenericParameterAttributes & GenericParameterAttributes.SpecialConstraintMask;
Dim sConstraints As GenericParameterAttributes = _ tp.GenericParameterAttributes And _ GenericParameterAttributes.SpecialConstraintMask
De särskilda villkorsattributen är flaggor och samma flagga (GenericParameterAttributes.None) som inte representerar några särskilda begränsningar representerar inte heller någon kovarians eller kontravarians. För att testa något av dessa villkor måste du därför använda lämplig mask. I det här fallet använder du GenericParameterAttributes.SpecialConstraintMask för att isolera de särskilda begränsningsflaggorna.
if (sConstraints == GenericParameterAttributes.None) { Console.WriteLine(" No special constraints."); } else { if (GenericParameterAttributes.None != (sConstraints & GenericParameterAttributes.DefaultConstructorConstraint)) { Console.WriteLine(" Must have a parameterless constructor."); } if (GenericParameterAttributes.None != (sConstraints & GenericParameterAttributes.ReferenceTypeConstraint)) { Console.WriteLine(" Must be a reference type."); } if (GenericParameterAttributes.None != (sConstraints & GenericParameterAttributes.NotNullableValueTypeConstraint)) { Console.WriteLine(" Must be a non-nullable value type."); } }
If sConstraints = GenericParameterAttributes.None Then Console.WriteLine(" No special constraints.") Else If GenericParameterAttributes.None <> (sConstraints And _ GenericParameterAttributes.DefaultConstructorConstraint) Then Console.WriteLine(" Must have a parameterless constructor.") End If If GenericParameterAttributes.None <> (sConstraints And _ GenericParameterAttributes.ReferenceTypeConstraint) Then Console.WriteLine(" Must be a reference type.") End If If GenericParameterAttributes.None <> (sConstraints And _ GenericParameterAttributes.NotNullableValueTypeConstraint) Then Console.WriteLine(" Must be a non-nullable value type.") End If End If
Konstruera en instans av en allmän typ
En allmän typ är som en mall. Du kan inte skapa instanser av den om du inte anger verkliga typer för dess allmänna typparametrar. För att göra detta vid körning med hjälp av reflektion krävs metoden MakeGenericType.
Hämta ett Type objekt som representerar den allmänna typen. Följande kod hämtar den allmänna typen Dictionary<TKey,TValue> på två olika sätt: genom att använda Type.GetType(String) metodöverlagring med en sträng som beskriver typen och genom att anropa metoden GetGenericTypeDefinition på den konstruerade typen
Dictionary\<String, Example>
(Dictionary(Of String, Example)
i Visual Basic). Metoden MakeGenericType kräver en allmän typdefinition.// Use the typeof operator to create the generic type // definition directly. To specify the generic type definition, // omit the type arguments but retain the comma that separates // them. Type d1 = typeof(Dictionary<,>); // You can also obtain the generic type definition from a // constructed class. In this case, the constructed class // is a dictionary of Example objects, with String keys. Dictionary<string, Example> d2 = []; // Get a Type object that represents the constructed type, // and from that get the generic type definition. The // variables d1 and d4 contain the same type. Type d3 = d2.GetType(); Type d4 = d3.GetGenericTypeDefinition();
' Use the GetType operator to create the generic type ' definition directly. To specify the generic type definition, ' omit the type arguments but retain the comma that separates ' them. Dim d1 As Type = GetType(Dictionary(Of ,)) ' You can also obtain the generic type definition from a ' constructed class. In this case, the constructed class ' is a dictionary of Example objects, with String keys. Dim d2 As New Dictionary(Of String, Example) ' Get a Type object that represents the constructed type, ' and from that get the generic type definition. The ' variables d1 and d4 contain the same type. Dim d3 As Type = d2.GetType() Dim d4 As Type = d3.GetGenericTypeDefinition()
Konstruera en matris med typargument som ersättning för typparametrarna. Matrisen måste innehålla rätt antal Type objekt i samma ordning som de visas i typparameterlistan. I det här fallet är nyckeln (första typparametern) av typen Stringoch värdena i ordlistan är instanser av en klass med namnet
Example
.Type[] typeArgs = [typeof(string), typeof(Example)];
Dim typeArgs() As Type = _ {GetType(String), GetType(Example)}
Anropa metoden MakeGenericType för att binda typargumenten till typparametrarna och konstruera typen.
Type constructed = d1.MakeGenericType(typeArgs);
Dim constructed As Type = _ d1.MakeGenericType(typeArgs)
Använd metodöverladdning för CreateInstance(Type) för att skapa ett objekt av den konstruerade typen. Följande kod lagrar två instanser av
Example
-klassen i det resulterandeDictionary<String, Example>
objektet._ = Activator.CreateInstance(constructed);
Dim o As Object = Activator.CreateInstance(constructed)
Exempel
I följande kodexempel definieras en DisplayGenericType
metod för att undersöka de generiska typdefinitioner och konstruerade typer som används i koden och visa deras information. Metoden DisplayGenericType
visar hur du använder egenskaperna IsGenericType, IsGenericParameteroch GenericParameterPosition och metoden GetGenericArguments.
Exemplet definierar också en DisplayGenericParameter
metod för att undersöka en allmän typparameter och visa dess begränsningar.
Kodexemplet definierar en uppsättning testtyper, inklusive en allmän typ som illustrerar typparameterbegränsningar och visar hur du visar information om dessa typer.
Exemplet konstruerar en typ från klassen Dictionary<TKey,TValue> genom att skapa en matris med typargument och anropa metoden MakeGenericType. Programmet jämför det Type objekt som skapats med MakeGenericType med ett Type objekt som hämtats med hjälp av typeof
(GetType
i Visual Basic), vilket visar att de är desamma. På samma sätt använder programmet metoden GetGenericTypeDefinition för att hämta den generiska typdefinitionen av den konstruerade typen och jämför den med det Type objekt som representerar klassen Dictionary<TKey,TValue>.
using System.Reflection;
// Define an example interface.
public interface ITestArgument { }
// Define an example base class.
public class TestBase { }
// Define a generic class with one parameter. The parameter
// has three constraints: It must inherit TestBase, it must
// implement ITestArgument, and it must have a parameterless
// constructor.
public class Test<T> where T : TestBase, ITestArgument, new() { }
// Define a class that meets the constraints on the type
// parameter of class Test.
public class TestArgument : TestBase, ITestArgument
{
public TestArgument() { }
}
public class Example
{
// The following method displays information about a generic
// type.
private static void DisplayGenericType(Type t)
{
Console.WriteLine($"\r\n {t}");
Console.WriteLine($" Is this a generic type? {t.IsGenericType}");
Console.WriteLine($" Is this a generic type definition? {t.IsGenericTypeDefinition}");
// Get the generic type parameters or type arguments.
Type[] typeParameters = t.GetGenericArguments();
Console.WriteLine($" List {typeParameters.Length} type arguments:");
foreach (Type tParam in typeParameters)
{
if (tParam.IsGenericParameter)
{
DisplayGenericParameter(tParam);
}
else
{
Console.WriteLine($" Type argument: {tParam}");
}
}
}
// Displays information about a generic type parameter.
private static void DisplayGenericParameter(Type tp)
{
Console.WriteLine($" Type parameter: {tp.Name} position {tp.GenericParameterPosition}");
foreach (Type iConstraint in tp.GetGenericParameterConstraints())
{
if (iConstraint.IsInterface)
{
Console.WriteLine($" Interface constraint: {iConstraint}");
}
}
Console.WriteLine($" Base type constraint: {tp.BaseType ?? tp.BaseType: None}");
GenericParameterAttributes sConstraints =
tp.GenericParameterAttributes &
GenericParameterAttributes.SpecialConstraintMask;
if (sConstraints == GenericParameterAttributes.None)
{
Console.WriteLine(" No special constraints.");
}
else
{
if (GenericParameterAttributes.None != (sConstraints &
GenericParameterAttributes.DefaultConstructorConstraint))
{
Console.WriteLine(" Must have a parameterless constructor.");
}
if (GenericParameterAttributes.None != (sConstraints &
GenericParameterAttributes.ReferenceTypeConstraint))
{
Console.WriteLine(" Must be a reference type.");
}
if (GenericParameterAttributes.None != (sConstraints &
GenericParameterAttributes.NotNullableValueTypeConstraint))
{
Console.WriteLine(" Must be a non-nullable value type.");
}
}
}
public static void Main()
{
// Two ways to get a Type object that represents the generic
// type definition of the Dictionary class.
// Use the typeof operator to create the generic type
// definition directly. To specify the generic type definition,
// omit the type arguments but retain the comma that separates
// them.
Type d1 = typeof(Dictionary<,>);
// You can also obtain the generic type definition from a
// constructed class. In this case, the constructed class
// is a dictionary of Example objects, with String keys.
Dictionary<string, Example> d2 = [];
// Get a Type object that represents the constructed type,
// and from that get the generic type definition. The
// variables d1 and d4 contain the same type.
Type d3 = d2.GetType();
Type d4 = d3.GetGenericTypeDefinition();
// Display information for the generic type definition, and
// for the constructed type Dictionary<String, Example>.
DisplayGenericType(d1);
DisplayGenericType(d2.GetType());
// Construct an array of type arguments to substitute for
// the type parameters of the generic Dictionary class.
// The array must contain the correct number of types, in
// the same order that they appear in the type parameter
// list of Dictionary. The key (first type parameter)
// is of type string, and the type to be contained in the
// dictionary is Example.
Type[] typeArgs = [typeof(string), typeof(Example)];
// Construct the type Dictionary<String, Example>.
Type constructed = d1.MakeGenericType(typeArgs);
DisplayGenericType(constructed);
_ = Activator.CreateInstance(constructed);
Console.WriteLine("\r\nCompare types obtained by different methods:");
Console.WriteLine($" Are the constructed types equal? {d2.GetType() == constructed}");
Console.WriteLine($" Are the generic definitions equal? {d1 == constructed.GetGenericTypeDefinition()}");
// Demonstrate the DisplayGenericType and
// DisplayGenericParameter methods with the Test class
// defined above. This shows base, interface, and special
// constraints.
DisplayGenericType(typeof(Test<>));
}
}
Imports System.Reflection
Imports System.Collections.Generic
' Define an example interface.
Public Interface ITestArgument
End Interface
' Define an example base class.
Public Class TestBase
End Class
' Define a generic class with one parameter. The parameter
' has three constraints: It must inherit TestBase, it must
' implement ITestArgument, and it must have a parameterless
' constructor.
Public Class Test(Of T As {TestBase, ITestArgument, New})
End Class
' Define a class that meets the constraints on the type
' parameter of class Test.
Public Class TestArgument
Inherits TestBase
Implements ITestArgument
Public Sub New()
End Sub
End Class
Public Class Example
' The following method displays information about a generic
' type.
Private Shared Sub DisplayGenericType(ByVal t As Type)
Console.WriteLine(vbCrLf & t.ToString())
Console.WriteLine(" Is this a generic type? " _
& t.IsGenericType)
Console.WriteLine(" Is this a generic type definition? " _
& t.IsGenericTypeDefinition)
' Get the generic type parameters or type arguments.
Dim typeParameters() As Type = t.GetGenericArguments()
Console.WriteLine(" List {0} type arguments:", _
typeParameters.Length)
For Each tParam As Type In typeParameters
If tParam.IsGenericParameter Then
DisplayGenericParameter(tParam)
Else
Console.WriteLine(" Type argument: {0}", _
tParam)
End If
Next
End Sub
' The following method displays information about a generic
' type parameter. Generic type parameters are represented by
' instances of System.Type, just like ordinary types.
Private Shared Sub DisplayGenericParameter(ByVal tp As Type)
Console.WriteLine(" Type parameter: {0} position {1}", _
tp.Name, tp.GenericParameterPosition)
Dim classConstraint As Type = Nothing
For Each iConstraint As Type In tp.GetGenericParameterConstraints()
If iConstraint.IsInterface Then
Console.WriteLine(" Interface constraint: {0}", _
iConstraint)
End If
Next
If classConstraint IsNot Nothing Then
Console.WriteLine(" Base type constraint: {0}", _
tp.BaseType)
Else
Console.WriteLine(" Base type constraint: None")
End If
Dim sConstraints As GenericParameterAttributes = _
tp.GenericParameterAttributes And _
GenericParameterAttributes.SpecialConstraintMask
If sConstraints = GenericParameterAttributes.None Then
Console.WriteLine(" No special constraints.")
Else
If GenericParameterAttributes.None <> (sConstraints And _
GenericParameterAttributes.DefaultConstructorConstraint) Then
Console.WriteLine(" Must have a parameterless constructor.")
End If
If GenericParameterAttributes.None <> (sConstraints And _
GenericParameterAttributes.ReferenceTypeConstraint) Then
Console.WriteLine(" Must be a reference type.")
End If
If GenericParameterAttributes.None <> (sConstraints And _
GenericParameterAttributes.NotNullableValueTypeConstraint) Then
Console.WriteLine(" Must be a non-nullable value type.")
End If
End If
End Sub
Public Shared Sub Main()
' Two ways to get a Type object that represents the generic
' type definition of the Dictionary class.
'
' Use the GetType operator to create the generic type
' definition directly. To specify the generic type definition,
' omit the type arguments but retain the comma that separates
' them.
Dim d1 As Type = GetType(Dictionary(Of ,))
' You can also obtain the generic type definition from a
' constructed class. In this case, the constructed class
' is a dictionary of Example objects, with String keys.
Dim d2 As New Dictionary(Of String, Example)
' Get a Type object that represents the constructed type,
' and from that get the generic type definition. The
' variables d1 and d4 contain the same type.
Dim d3 As Type = d2.GetType()
Dim d4 As Type = d3.GetGenericTypeDefinition()
' Display information for the generic type definition, and
' for the constructed type Dictionary(Of String, Example).
DisplayGenericType(d1)
DisplayGenericType(d2.GetType())
' Construct an array of type arguments to substitute for
' the type parameters of the generic Dictionary class.
' The array must contain the correct number of types, in
' the same order that they appear in the type parameter
' list of Dictionary. The key (first type parameter)
' is of type string, and the type to be contained in the
' dictionary is Example.
Dim typeArgs() As Type = _
{GetType(String), GetType(Example)}
' Construct the type Dictionary(Of String, Example).
Dim constructed As Type = _
d1.MakeGenericType(typeArgs)
DisplayGenericType(constructed)
Dim o As Object = Activator.CreateInstance(constructed)
Console.WriteLine(vbCrLf & _
"Compare types obtained by different methods:")
Console.WriteLine(" Are the constructed types equal? " _
& (d2.GetType() Is constructed))
Console.WriteLine(" Are the generic definitions equal? " _
& (d1 Is constructed.GetGenericTypeDefinition()))
' Demonstrate the DisplayGenericType and
' DisplayGenericParameter methods with the Test class
' defined above. This shows base, interface, and special
' constraints.
DisplayGenericType(GetType(Test(Of )))
End Sub
End Class