Einschränkungen für Typparameter (C#-Programmierhandbuch)Constraints on Type Parameters (C# Programming Guide)

Wenn Sie eine generische Klasse definieren, können Sie Beschränkungen auf die Arten der Typen anwenden, die Clientcode für generische Typargumente verwenden kann, wenn er Ihre Klasse instanziiert.When you define a generic class, you can apply restrictions to the kinds of types that client code can use for type arguments when it instantiates your class. Wenn Clientcode versucht, Ihre Klasse zu instanziieren, indem er einen Typ verwendet, der durch Ihre Einschränkung nicht erlaubt ist, kommt es zu einem Kompilierzeitfehler.If client code tries to instantiate your class by using a type that is not allowed by a constraint, the result is a compile-time error. Diese Einschränkungen werden als Constraints bezeichnet.These restrictions are called constraints. Constraints werden mit dem kontextuellen Schlüsselwort where angegeben.Constraints are specified by using the where contextual keyword. In der folgenden Tabelle werden die sechs verschiedenen Contrainttypen aufgelistet:The following table lists the six types of constraints:

ConstraintConstraint BeschreibungDescription
where T: structwhere T: struct Das Typargument muss ein Werttyp sein.The type argument must be a value type. Jeder Werttyp außer Nullable kann angegeben werden.Any value type except Nullable can be specified. Weitere Informationen finden Sie unter Using Nullable Types (Verwenden von Nullable-Typen).See Using Nullable Types for more information.
where T : classwhere T : class Das Typargument muss ein Verweistyp sein. Dies gilt ebenfalls für Klassen-, Schnittstellen-, Delegat- oder Arraytypen.The type argument must be a reference type; this applies also to any class, interface, delegate, or array type.
where T : new()where T : new() Das Typargument muss einen öffentlichen, parameterlosen Konstruktor aufweisen.The type argument must have a public parameterless constructor. Beim gemeinsamen Verwenden anderen Constraints muss der new()-Constraint zuletzt angegeben werden.When used together with other constraints, the new() constraint must be specified last.
where T : <basisklassenname>where T : <base class name> Das Typargument muss die angegebene Basisklasse sein oder von dieser abgeleitet werden.The type argument must be or derive from the specified base class.
where T : <schnittstellenname>where T : <interface name> Das Typargument muss die angegebene Schnittstelle sein oder diese implementieren.The type argument must be or implement the specified interface. Es können mehrere Schnittstelleneinschränkungen angegeben werden.Multiple interface constraints can be specified. Die einschränkende Schnittstelle kann auch generisch sein.The constraining interface can also be generic.
where T : Uwhere T : U Das Typargument, das für T angegeben wurde, muss das für T angegebene Argument sein oder von diesem abgeleitet werden.The type argument supplied for T must be or derive from the argument supplied for U.

Weshalb Constraints?Why Use Constraints

Wenn Sie untersuchen möchten, ob ein bestimmtes Argument in einer generischen Liste gültig ist oder es mit einem anderen Element vergleichen möchten, muss der Compiler eine Garantie haben, dass der Operator oder die Methode, die er aufgerufen hat, von jedem Typargument unterstützt wird, das von Clientcode angegeben werden kann.If you want to examine an item in a generic list to determine whether it is valid or to compare it to some other item, the compiler must have some guarantee that the operator or method it has to call will be supported by any type argument that might be specified by client code. Diese Garantie wird gegeben, indem Sie einen oder mehrere Constraints auf Ihre generische Klassendefinition anwenden.This guarantee is obtained by applying one or more constraints to your generic class definition. Der Basisklassenconstraint sagt dem Compiler z.B., dass nur Objekte dieses Typs oder Objekte, die von diesem Typ abgeleitet werden, als Typargumente verwendet werden.For example, the base class constraint tells the compiler that only objects of this type or derived from this type will be used as type arguments. Sobald der Compiler diese Garantie hat, kann er erlauben, dass Methoden dieses Typs in der generischen Klasse aufgerufen werden können.Once the compiler has this guarantee, it can allow methods of that type to be called in the generic class. Constraints werden mit dem kontextuellen Schlüsselwort where angewendet.Constraints are applied by using the contextual keyword where. Im folgenden Codebeispiel wird die Funktionalität veranschaulicht, die der GenericList<T>-Klasse durch das Anwenden eines Basisklassenconstraints hinzugefügt werden kann (in Einführung in Generika).The following code example demonstrates the functionality we can add to the GenericList<T> class (in Introduction to Generics) by applying a base class constraint.

public class Employee
{
    private string name;
    private int id;

    public Employee(string s, int i)
    {
        name = s;
        id = i;
    }

    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    public int ID
    {
        get { return id; }
        set { id = value; }
    }
}

public class GenericList<T> where T : Employee
{
    private class Node
    {
        private Node next;
        private T data;

        public Node(T t)
        {
            next = null;
            data = t;
        }

        public Node Next
        {
            get { return next; }
            set { next = value; }
        }

        public T Data
        {
            get { return data; }
            set { data = value; }
        }
    }

    private Node head;

    public GenericList() //constructor
    {
        head = null;
    }

    public void AddHead(T t)
    {
        Node n = new Node(t);
        n.Next = head;
        head = n;
    }

    public IEnumerator<T> GetEnumerator()
    {
        Node current = head;

        while (current != null)
        {
            yield return current.Data;
            current = current.Next;
        }
    }

    public T FindFirstOccurrence(string s)
    {
        Node current = head;
        T t = null;

        while (current != null)
        {
            //The constraint enables access to the Name property.
            if (current.Data.Name == s)
            {
                t = current.Data;
                break;
            }
            else
            {
                current = current.Next;
            }
        }
        return t;
    }
}

Mit dem Constraint kann die generische Klasse die Employee.Name-Eigenschaft verwenden, da alle Elemente des Typs T sicher ein Employee-Objekt oder ein Objekt, das von Employee erbt, sind.The constraint enables the generic class to use the Employee.Name property because all items of type T are guaranteed to be either an Employee object or an object that inherits from Employee.

Mehrere Constraints können wie folgt auf den gleichen Typenparameter angewendet werden, und die Contraints können selbst generische Typen sein:Multiple constraints can be applied to the same type parameter, and the constraints themselves can be generic types, as follows:

class EmployeeList<T> where T : Employee, IEmployee, System.IComparable<T>, new()
{
    // ...
}

Indem Sie den Typparameter einschränken, erhöhen Sie die Zahl an zulässigen Vorgängen und Methodenaufrufen von denjenigen, die vom einschränkenden Typ und allen Typen in dessen Vererbungshierarchie unterstützt werden.By constraining the type parameter, you increase the number of allowable operations and method calls to those supported by the constraining type and all types in its inheritance hierarchy. Beim Entwerfen generischer Klassen und Methoden müssen Sie Constraints auf den Typparameter anwenden, wenn Sie Vorgänge mit den generischen Membern durchführen möchten, die über das einfache Zuweisen und Aufrufen von Methoden hinausgehen, die nicht von System.Object unterstützt werden.Therefore, when you design generic classes or methods, if you will be performing any operation on the generic members beyond simple assignment or calling any methods not supported by System.Object, you will have to apply constraints to the type parameter.

Wenn Sie den Constraint where T : class anwenden, vermeiden Sie das Verwenden der Operatoren == und != mit dem Typparameter, da diese nur auf Verweisidentität und nicht auf Wertgleichheit prüfen.When applying the where T : class constraint, avoid the == and != operators on the type parameter because these operators will test for reference identity only, not for value equality. Dies ist auch der Fall, wenn diese Operatoren in einem Typ überladen werden, der als Argument verwendet wird.This is the case even if these operators are overloaded in a type that is used as an argument. Der folgende Code veranschaulicht diesen Aspekt. Die Ausgabe ist FALSE, obwohl die String-Klasse den ==-Operator überlädt.The following code illustrates this point; the output is false even though the String class overloads the == operator.

public static void OpTest<T>(T s, T t) where T : class
{
    System.Console.WriteLine(s == t);
}
static void Main()
{
    string s1 = "target";
    System.Text.StringBuilder sb = new System.Text.StringBuilder("target");
    string s2 = sb.ToString();
    OpTest<string>(s1, s2);
}

Dieses Verhalten tritt auf, da der Compiler zur Kompilierzeit nur weiß, dass T ein Verweistyp ist, und deshalb die Standardoperatoren verwenden muss, die für alle Verweistypen zulässig sind.The reason for this behavior is that, at compile time, the compiler only knows that T is a reference type, and therefore must use the default operators that are valid for all reference types. Wenn Sie auf Wertgleichheit prüfen müssen, wird empfohlen, dass Sie den where T : IComparable<T>-Constraint anwenden und die Schnittstelle in jeder Klasse implementieren, die verwendet wird, um die generische Klasse zu erstellen.If you must test for value equality, the recommended way is to also apply the where T : IComparable<T> constraint and implement that interface in any class that will be used to construct the generic class.

Einschränken mehrerer ParameterConstraining Multiple Parameters

Sie können wie im folgenden Beispiel gezeigt Constraints auf mehrere Parameter und mehrere Constraints auf einen einzelnen Parameter anwenden:You can apply constraints to multiple parameters, and multiple constraints to a single parameter, as shown in the following example:

class Base { }
class Test<T, U>
    where U : struct
    where T : Base, new() { }

Ungebundene TypparameterUnbounded Type Parameters

Typparameter, auf die keine Constraints angewendet wurden, wie z.B. T in der öffentlichen Klasse SampleClass<T>{}, werden als ungebundene Typparameter bezeichnet.Type parameters that have no constraints, such as T in public class SampleClass<T>{}, are called unbounded type parameters. Für ungebundene Typparameter gelten die folgenden Regeln:Unbounded type parameters have the following rules:

  • Die Operatoren != und == können nicht verwendet werden, weil es keine Garantie gibt, dass das jeweilige Typargument diese auch unterstützt.The != and == operators cannot be used because there is no guarantee that the concrete type argument will support these operators.

  • Sie können in und aus System.Object oder implizit in einen Schnittstellentyp konvertiert werden.They can be converted to and from System.Object or explicitly converted to any interface type.

  • Sie können mit NULL vergleichen.You can compare to null. Wenn ein ungebundener Parameter mit null verglichen wird, gibt der Vergleich immer FALSE zurück, wenn das Typargument ein Werttyp ist.If an unbounded parameter is compared to null, the comparison will always return false if the type argument is a value type.

Typparameter als ConstraintsType Parameters as Constraints

Es ist nützlich, einen Typparameter wie in folgendem Beispiel gezeigt als Constraint zu verwenden, wenn eine Memberfunktion mit ihren eigenen Typparametern diesen Parameter auf den Typparameter des enthaltenden Typs einschränken muss:The use of a generic type parameter as a constraint is useful when a member function with its own type parameter has to constrain that parameter to the type parameter of the containing type, as shown in the following example:

class List<T>
{
    void Add<U>(List<U> items) where U : T {/*...*/}
}

Im vorherigen Beispiel ist T ein Typconstraint im Kontext der Add-Methode und ein ungebundener Typparameter im Kontext der List-Klasse.In the previous example, T is a type constraint in the context of the Add method, and an unbounded type parameter in the context of the List class.

Typparameter können auch in generischen Klassendefinitionen als Constraints verwendet werden.Type parameters can also be used as constraints in generic class definitions. Beachten Sie, dass Typparameter in spitzen Klammern zusammen mit allen anderen Typparametern deklariert werden müssen.Note that the type parameter must be declared within the angle brackets together with any other type parameters:

//Type parameter V is used as a type constraint.
public class SampleClass<T, U, V> where T : V { }

Das Verwenden von Typparametern als Constraints für generische Klassen ist nur bis zu einem gewissen Punkt nützlich, da der Compiler keine Informationen über den Typparameter annehmen kann, nur dass er von System.Object abgeleitet ist.The usefulness of type parameters as constraints with generic classes is very limited because the compiler can assume nothing about the type parameter except that it derives from System.Object. Sie sollten Typparameter als Constraints dann verwenden, wenn Sie eine Vererbungsbeziehung zwischen zwei Typparametern erzwingen möchten.Use type parameters as constraints on generic classes in scenarios in which you want to enforce an inheritance relationship between two type parameters.

Siehe auchSee Also

System.Collections.Generic
C#-ProgrammierhandbuchC# Programming Guide
Einführung in GenerikaIntroduction to Generics
Generische KlassenGeneric Classes
new-Einschränkungnew Constraint