Reflektion och allmänna typer

När det gäller reflektion är skillnaden mellan en generisk typ och en vanlig typ att en generisk typ har associerat med den en uppsättning typparametrar (om det är en generisk typdefinition) eller typargument (om det är en konstruerad typ). En generisk metod skiljer sig från en vanlig metod på samma sätt.

Det finns två nycklar för att förstå hur reflektion hanterar allmänna typer och metoder:

  • Typparametrarna för generiska typdefinitioner och generiska metoddefinitioner representeras av instanser av Type klassen.

    Kommentar

    Många egenskaper och metoder för Type har olika beteende när ett Type objekt representerar en allmän typparameter. Dessa skillnader dokumenteras i egenskaps- och metodartiklarna. Se till exempel IsAutoClass och DeclaringType. Dessutom är vissa medlemmar endast giltiga när ett Type objekt representerar en allmän typparameter. Se till exempel GetGenericTypeDefinition.

  • Om en instans av Type representerar en allmän typ innehåller den en matris med typer som representerar typparametrarna (för generiska typdefinitioner) eller typargumenten (för konstruerade typer). Detsamma gäller för en instans av MethodInfo klassen som representerar en generisk metod.

Reflektion innehåller metoder för Type och MethodInfo som gör att du kan komma åt matrisen med typparametrar och avgöra om en instans av Type representerar en typparameter eller en faktisk typ.

Exempel på kod som visar de metoder som beskrivs här finns i Så här: Granska och instansiera generiska typer med reflektion.

Följande diskussion förutsätter att du är bekant med terminologin för generiska objekt, till exempel skillnaden mellan typparametrar och argument och öppna eller stängda konstruerade typer. Mer information finns i Generiska objekt.

Är det här en allmän typ eller metod?

När du använder reflektion för att undersöka en okänd typ, som representeras av en instans av Type, använder du IsGenericType egenskapen för att avgöra om den okända typen är generisk. Den returnerar true om typen är generisk. När du undersöker en okänd metod, som representeras av en instans av MethodInfo klassen, använder IsGenericMethod du på samma sätt egenskapen för att avgöra om metoden är generisk.

Är detta en allmän typ eller metoddefinition?

Använd egenskapen IsGenericTypeDefinition för att avgöra om ett Type objekt representerar en allmän typdefinition och använd IsGenericMethodDefinition metoden för att avgöra om en MethodInfo representerar en allmän metoddefinition.

Generiska typ- och metoddefinitioner är de mallar som instanserbara typer skapas från. Generiska typer i .NET-biblioteken, till exempel Dictionary<TKey,TValue>, är generiska typdefinitioner.

Är typen eller metoden öppen eller stängd?

En allmän typ eller metod stängs om instanserbara typer har ersatts med alla dess typparametrar, inklusive alla typparametrar för alla omslutande typer. Du kan bara skapa en instans av en allmän typ om den stängs. Egenskapen Type.ContainsGenericParameters returnerar true om en typ är öppen. För metoder MethodBase.ContainsGenericParameters utför metoden samma funktion.

Generera stängda generiska typer

När du har en allmän typ eller metoddefinition använder du metoden för att skapa en sluten MakeGenericType allmän typ eller metoden för att skapa en MethodInfo för en sluten MakeGenericMethod allmän metod.

Hämta den allmänna typen eller metoddefinitionen

Om du har en öppen allmän typ eller metod som inte är en allmän typ eller metoddefinition kan du inte skapa instanser av den och du kan inte ange de typparametrar som saknas. Du måste ha en allmän typ eller metoddefinition. GetGenericTypeDefinition Använd metoden för att hämta den generiska typdefinitionen GetGenericMethodDefinition eller metoden för att hämta den generiska metoddefinitionen.

Om du till exempel har ett Type objekt som representerar Dictionary<int, string> och du vill skapa typen Dictionary<string, MyClass>kan du använda GetGenericTypeDefinition metoden för att hämta en Type representerare Dictionary<TKey, TValue> och sedan använda MakeGenericType metoden för att skapa en Type som representerar Dictionary<int, MyClass>.

Ett exempel på en öppen allmän typ som inte är en allmän typ finns i Typparameter eller typargument.

Granska typargument och typparametrar

Type.GetGenericArguments Använd metoden för att hämta en matris med Type objekt som representerar typparametrar eller typargument av en allmän typ och använd MethodInfo.GetGenericArguments metoden för att göra samma sak för en generisk metod.

När du vet att ett Type objekt representerar en typparameter finns det många ytterligare frågor som kan besvaras. Du kan fastställa typparameterns källa, dess position och dess begränsningar.

Typparameter eller typargument

Använd egenskapen för att avgöra om ett visst element i matrisen är en typparameter eller ett typargument IsGenericParameter . Egenskapen IsGenericParameter är true om elementet är en typparameter.

En allmän typ kan vara öppen utan att vara en allmän typdefinition, i vilket fall den har en blandning av typargument och typparametrar. I följande kod härleds till exempel klassen D från en typ som skapats genom att ersätta den första typparametern D för för den andra typparametern för B.

class B<T, U> {}
class D<V, W> : B<int, V> {}
Class B(Of T, U)
End Class
Class D(Of V, W)
    Inherits B(Of Integer, V)
End Class
generic<typename T, typename U> ref class B {};
generic<typename V, typename W> ref class D : B<int, V> {};

Om du hämtar ett Type objekt som representerar D<V, W> och använder BaseType egenskapen för att hämta dess bastyp är resultatet type B<int, V> öppet, men det är inte en allmän typdefinition.

Källa för en allmän parameter

En generisk typparameter kan komma från den typ som du undersöker, från en omslutande typ eller från en allmän metod. Du kan fastställa källan till den generiska typparametern på följande sätt:

  • DeclaringMethod Använd först egenskapen för att avgöra om typparametern kommer från en generisk metod. Om egenskapsvärdet inte är en null-referens är källan en allmän metod.
  • Om källan inte är en generisk metod använder du DeclaringType egenskapen för att fastställa den generiska typ som parametern för generisk typ tillhör.

Om typparametern tillhör en generisk metod DeclaringType returnerar egenskapen den typ som deklarerade den generiska metoden, vilket är irrelevant.

Position för en allmän parameter

I sällsynta fall är det nödvändigt att fastställa positionen för en typparameter i typparameterlistan för den deklarerande klassen. Anta till exempel att du har ett Type objekt som representerar B<int, V> typen från föregående exempel. Metoden GetGenericArguments ger dig en lista med typargument, och när du undersöker V kan du använda DeclaringMethod egenskaperna och DeclaringType för att identifiera var den kommer ifrån. Du kan sedan använda GenericParameterPosition egenskapen för att fastställa dess position i typparameterlistan där den definierades. I det här exemplet V är position 0 (noll) i listan med typparametern där den definierades.

Begränsningar för bastyp och gränssnitt

GetGenericParameterConstraints Använd metoden för att hämta grundtypsbegränsningarna och gränssnittsbegränsningarna för en typparameter. Ordningen på elementen i matrisen är inte betydande. Ett element representerar en gränssnittsbegränsning om det är en gränssnittstyp.

Generiska parameterattribut

Egenskapen GenericParameterAttributes hämtar ett GenericParameterAttributes värde som anger variansen (kovarians eller kontravarians) och de särskilda begränsningarna för en typparameter.

Kovarians och kontravarians

Om du vill avgöra om en typparameter är covariant eller kontravariant använder du masken GenericParameterAttributes.VarianceMask för det GenericParameterAttributes värde som returneras av GenericParameterAttributes egenskapen. Om resultatet är GenericParameterAttributes.Noneär typparametern invariant. Mer information finns i Covariance och Contravariance.

Särskilda begränsningar

Om du vill fastställa de särskilda begränsningarna för en typparameter använder du masken GenericParameterAttributes.SpecialConstraintMask för det GenericParameterAttributes värde som returneras av GenericParameterAttributes egenskapen. Om resultatet är GenericParameterAttributes.Nonefinns det inga särskilda begränsningar. En typparameter kan begränsas till att vara en referenstyp, vara en värdetyp som inte kan nulliseras och ha en parameterlös konstruktor.

Invariants

En tabell med de invarianta villkoren för vanliga termer i reflektion för generiska typer finns Type.IsGenericTypei . Mer information om allmänna metoder finns i MethodBase.IsGenericMethod.