Share via


Generics i .NET

Med generiska data kan du skräddarsy en metod, klass, struktur eller ett gränssnitt efter den exakta datatyp som den fungerar på. I stället för att använda Hashtable klassen , som gör att nycklar och värden kan vara av valfri typ, kan du till exempel använda den Dictionary<TKey,TValue> allmänna klassen och ange vilka typer som tillåts för nyckeln och värdet. Bland fördelarna med generiska läkemedel finns ökad återanvändning av kod och typsäkerhet.

Definiera och använda generiska data

Generiska objekt är klasser, strukturer, gränssnitt och metoder som har platshållare (typparametrar) för en eller flera av de typer som de lagrar eller använder. En generisk samlingsklass kan använda en typparameter som platshållare för den typ av objekt som den lagrar. typparametrarna visas som typer av fält och parametertyperna för dess metoder. En generisk metod kan använda sin typparameter som typ av returvärde eller som typ av en av dess formella parametrar. Följande kod illustrerar en enkel generisk klassdefinition.

generic<typename T>
public ref class Generics
{
public:
    T Field;
};
public class Generic<T>
{
    public T Field;
}
Public Class Generic(Of T)
    Public Field As T

End Class

När du skapar en instans av en generisk klass anger du de faktiska typerna som ska ersätta typparametrarna. Detta etablerar en ny generisk klass, som kallas en konstruerad generisk klass, där de valda typerna ersätts överallt där typparametrarna visas. Resultatet är en typsäker klass som är anpassad efter dina val av typer, vilket visas i följande kod.

static void Main()
{
    Generics<String^>^ g = gcnew Generics<String^>();
    g->Field = "A string";
    //...
    Console::WriteLine("Generics.Field           = \"{0}\"", g->Field);
    Console::WriteLine("Generics.Field.GetType() = {0}", g->Field->GetType()->FullName);
}
public static void Main()
{
    Generic<string> g = new Generic<string>();
    g.Field = "A string";
    //...
    Console.WriteLine("Generic.Field           = \"{0}\"", g.Field);
    Console.WriteLine("Generic.Field.GetType() = {0}", g.Field.GetType().FullName);
}
Public Shared Sub Main()
    Dim g As New Generic(Of String)
    g.Field = "A string"
    '...
    Console.WriteLine("Generic.Field           = ""{0}""", g.Field)
    Console.WriteLine("Generic.Field.GetType() = {0}", g.Field.GetType().FullName)
End Sub

Terminologi för generiska termer

Följande termer används för att diskutera generiska ämnen i .NET:

  • En generisk typdefinition är en klass-, struktur- eller gränssnittsdeklaration som fungerar som en mall, med platshållare för de typer som den kan innehålla eller använda. Klassen kan till exempel System.Collections.Generic.Dictionary<TKey,TValue> innehålla två typer: nycklar och värden. Eftersom en generisk typdefinition bara är en mall kan du inte skapa instanser av en klass, struktur eller ett gränssnitt som är en generisk typdefinition.

  • Parametrar av allmän typ, eller typparametrar, är platshållarna i en generisk typ- eller metoddefinition. Den System.Collections.Generic.Dictionary<TKey,TValue> generiska typen har två typparametrar, TKey och TValue, som representerar typerna av dess nycklar och värden.

  • En konstruerad generisk typ, eller en konstruerad typ, är resultatet av att ange typer för parametrar av generisk typ för en generisk typdefinition.

  • Ett generiskt typargument är vilken typ som helst som ersätts med en generisk typparameter.

  • Den allmänna termen generisk typ innehåller både konstruerade typer och generiska typdefinitioner.

  • Med kovarians och kontravarians för parametrar av generisk typ kan du använda konstruerade generiska typer vars typargument är mer härledda (kovarians) eller mindre härledda (kontravariance) än en målkonstruerad typ. Kovarians och kontravariation kallas gemensamt varians. Mer information finns i Kovarians och Kontravarians.

  • Begränsningar är begränsningar för parametrar av allmän typ. Du kan till exempel begränsa en typparameter till typer som implementerar det System.Collections.Generic.IComparer<T> allmänna gränssnittet för att säkerställa att instanser av typen kan sorteras. Du kan också begränsa typparametrar till typer som har en viss basklass, som har en parameterlös konstruktor eller som är referenstyper eller värdetyper. Användare av den allmänna typen kan inte ersätta typargument som inte uppfyller begränsningarna.

  • En generisk metoddefinition är en metod med två parameterlistor: en lista över generiska typparametrar och en lista över formella parametrar. Typparametrar kan visas som returtyp eller som typer av formella parametrar, som följande kod visar.

generic<typename T>
T Generic(T arg)
{
    T temp = arg;
    //...
    return temp;
}
T Generic<T>(T arg)
{
    T temp = arg;
    //...
    return temp;
}
Function Generic(Of T)(ByVal arg As T) As T
    Dim temp As T = arg
    '...
    Return temp
End Function

Generiska metoder kan visas på generiska eller icke-generiska typer. Det är viktigt att notera att en metod inte är generisk bara för att den tillhör en generisk typ, eller ens för att den har formella parametrar vars typer är de generiska parametrarna för den omslutande typen. En metod är endast generisk om den har en egen lista med typparametrar. I följande kod är endast metoden G generisk.

ref class A
{
    generic<typename T>
    T G(T arg)
    {
        T temp = arg;
        //...
        return temp;
    }
};
generic<typename T>
ref class Generic
{
    T M(T arg)
    {
        T temp = arg;
        //...
        return temp;
    }
};
class A
{
    T G<T>(T arg)
    {
        T temp = arg;
        //...
        return temp;
    }
}
class Generic<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 Generic(Of T)
    Function M(ByVal arg As T) As T
        Dim temp As T = arg
        '...
        Return temp
    End Function
End Class

Fördelar och nackdelar med generiska läkemedel

Det finns många fördelar med att använda allmänna samlingar och ombud:

  • Typsäkerhet. Generiska objekt flyttar belastningen av typsäkerhet från dig till kompilatorn. Du behöver inte skriva kod för att testa rätt datatyp eftersom den framtvingas vid kompilering. Behovet av typkondering och risken för körningsfel minskar.

  • Mindre kod och mindre kod återanvänds enklare. Du behöver inte ärva från en bastyp och åsidosätta medlemmar. Är till exempel LinkedList<T> redo för omedelbar användning. Du kan till exempel skapa en länkad lista med strängar med följande variabeldeklaration:

    LinkedList<String^>^ llist = gcnew LinkedList<String^>();
    
    LinkedList<string> llist = new LinkedList<string>();
    
    Dim llist As New LinkedList(Of String)()
    
  • Bättre prestanda. Allmänna samlingstyper fungerar vanligtvis bättre för lagring och manipulering av värdetyper eftersom det inte finns något behov av att boxa värdetyperna.

  • Allmänna ombud aktiverar typsäkra återanrop utan att behöva skapa flera ombudsklasser. Med det allmänna ombudet Predicate<T> kan du till exempel skapa en metod som implementerar dina egna sökkriterier för en viss typ och använda din metod med metoder av typen Array , till exempel Find, FindLastoch FindAll.

  • Generics effektiviserar dynamiskt genererad kod. När du använder generiska objekt med dynamiskt genererad kod behöver du inte generera typen. Detta ökar antalet scenarier där du kan använda förenklade dynamiska metoder i stället för att generera hela sammansättningar. Mer information finns i Så här: Definiera och köra dynamiska metoder och DynamicMethod.

Följande är några begränsningar för generiska läkemedel:

  • Generiska typer kan härledas från de flesta basklasser, till exempel MarshalByRefObject (och begränsningar kan användas för att kräva att generiska typparametrar härleds från basklasser som MarshalByRefObject). .NET stöder dock inte kontextbundna generiska typer. En generisk typ kan härledas från ContextBoundObject, men om du försöker skapa en instans av den typen blir en TypeLoadException.

  • Uppräkningar kan inte ha allmänna typparametrar. En uppräkning kan bara vara generisk för övrigt (till exempel eftersom den är kapslad i en generisk typ som definieras med hjälp av Visual Basic, C#eller C++). Mer information finns i "Uppräkningar" i Common Type System.

  • Förenklade dynamiska metoder kan inte vara generiska.

  • I Visual Basic, C# och C++ kan en kapslad typ som omges av en generisk typ inte instansieras om inte typer har tilldelats till typparametrarna för alla omslutande typer. Ett annat sätt att säga detta är att i reflektion innehåller en kapslad typ som definieras med hjälp av dessa språk typparametrar för alla dess omslutande typer. På så sätt kan typparametrarna för omslutande typer användas i medlemsdefinitionerna för en kapslad typ. Mer information finns i "Kapslade typer" i MakeGenericType.

    Anteckning

    En kapslad typ som definieras genom att generera kod i en dynamisk sammansättning eller genom att användaIlasm.exe (IL Assembler) krävs inte för att inkludera typparametrarna för dess inneslutningstyper. Men om den inte innehåller dem finns typparametrarna inte i omfånget i den kapslade klassen.

    Mer information finns i "Kapslade typer" i MakeGenericType.

Stöd för klassbibliotek och språk

.NET tillhandahåller ett antal generiska samlingsklasser i följande namnområden:

Allmänna gränssnitt för implementering av sorterings- och likhetsjämförelser finns i System namnområdet, tillsammans med allmänna ombudstyper för händelsehanterare, konverteringar och sökpredikat.

Stöd för generiska objekt har lagts till i System.Reflection namnområdet för att undersöka generiska typer och generiska metoder, för att System.Reflection.Emit generera dynamiska sammansättningar som innehåller generiska typer och metoder samt för att System.CodeDom generera källdiagram som innehåller generiska objekt.

Common Language Runtime innehåller nya opcodes och prefix för att stödja generiska typer i Microsofts mellanliggande språk (MSIL), inklusive Stelem, Ldelem, Unbox_Any, Constrainedoch Readonly.

Visual C++, C# och Visual Basic ger alla fullt stöd för att definiera och använda generiska objekt. Mer information om språkstöd finns i Allmänna typer i Visual Basic, Introduktion till generiska objekt och Översikt över generiska objekt i Visual C++.

Kapslade typer och generiska objekt

En typ som är kapslad i en generisk typ kan bero på typparametrarna för den omslutande generiska typen. Den vanliga språkkörningen anser att kapslade typer är generiska, även om de inte har egna generiska typparametrar. När du skapar en instans av en kapslad typ måste du ange typargument för alla omslutande generiska typer.

Rubrik Beskrivning
Allmänna samlingar i .NET Beskriver generiska samlingsklasser och andra generiska typer i .NET.
Allmänna ombud för att manipulera matriser och listor Beskriver allmänna ombud för konverteringar, sökpredikat och åtgärder som ska vidtas på element i en matris eller samling.
Allmänna gränssnitt Beskriver allmänna gränssnitt som ger vanliga funktioner i olika familjer av generiska typer.
Kovarians och kontravarians Beskriver kovarians och kontravarians i generiska typparametrar.
Samlingstyper som används ofta Innehåller sammanfattningsinformation om egenskaper och användningsscenarier för samlingstyperna i .NET, inklusive generiska typer.
När generiska samlingar ska användas Beskriver allmänna regler för att avgöra när allmänna samlingstyper ska användas.
Anvisningar: Definiera en allmän typ med reflektionsavsändare Beskriver hur du genererar dynamiska sammansättningar som innehåller allmänna typer och metoder.
Generiska typer i Visual Basic Beskriver funktionen generics för Visual Basic användare, inklusive instruktioner för att använda och definiera generiska typer.
Introduktion till generiska Ger en översikt över hur du definierar och använder generiska typer för C#-användare.
Översikt över generiska objekt i Visual C++ Beskriver funktionen generics för C++-användare, inklusive skillnaderna mellan generiska objekt och mallar.

Referens

System.Collections.Generic

System.Collections.ObjectModel

System.Reflection.Emit.OpCodes