Home  >  Article  >  Backend Development  >  Detailed graphic and text introduction to where type constraints in C#

Detailed graphic and text introduction to where type constraints in C#

黄舟
黄舟Original
2017-03-03 13:17:471281browse

Constraints on Type Parameters (C# Programming Guide)

Visual Studio 2005





Other versions

When defining a generic class, you can Places restrictions on the kinds of types that client code can use for type parameters when instantiating a class. If client code attempts to instantiate a class using a type that is not allowed by a constraint, a compile-time error occurs. These limits are called constraints. Constraints are specified using the where context keyword. The following table lists the six types of constraints:

Constraint Description

T : Structure

type parameters must be value types. Any value type except Nullable can be specified. For more information, see Using Nullable Types (C# Programming Guide).

T: Class

Type parameters must be reference types, including any class, interface, delegate, or array type.

T: new()

Type parameters must have a parameterless public constructor. When used with other constraints, the new() constraint must be specified last.

T:51c4c8ea8417f6ad54861e90fe6443ea

The type parameter must be the specified base class or derived from The specified base class.

T:78e320a2a6f6b6b6ae209be01be63157

Type parameters must be the specified interface or implement the specified interface. Multiple interface constraints can be specified. Constraint interfaces can also be generic.

T: U

Type parameters provided for T must be parameters provided for U or derived from U parameters provided. This is called a naked type constraint.


Reasons for using constraints


If you want to check an item in a generic list to determine if it is valid, or compare it to some other item To make a comparison, the compiler must provide some assurance that the operator or method it needs to call will be supported by any type parameters that the client code may specify. This guarantee is obtained by applying one or more constraints to the generic class definition. For example, a base class constraint tells the compiler that only objects of this type or objects derived from this type can be used as type parameters. Once the compiler has this guarantee, it can allow calling methods of that type in a generic class. Constraints are applied using the context keyword where. The following code example demonstrates how to add base class constraints to the GenericList8742468051c85b06f0a0af9e3e506b5c class (in Introduction to Generics (C# Programming Guide)) function.

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;
    }
}

With constraint type parameters, you can increase the number of allowed operations and method calls supported by the constraint type and all types in its inheritance hierarchy. Therefore, when designing a generic class or method, if you want to do anything other than simple assignment to a generic member or call any method that is not supported by System.Object , you will need the type parameter Apply constraints.

When applying the where T : class constraint, it is recommended not to use the == and != operators on type parameters. Because these operators only test reference identity and not value equality. This is true even if these operators are overloaded in the type used as a parameter. The code below illustrates this; even though the String class overloads the == operator, the output is false.

C

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

The reason for this is that the compiler only knows at compile time that T is a reference type, so it must use the default operator that is valid for all reference types. If you need to test value equality, the recommended approach is to both apply the where T : IComparable8742468051c85b06f0a0af9e3e506b5c constraint and implement the interface in any class that will be used to construct the generic class.

Unbound type parameters



Unbound type parameters (such as public class SampleClass4227aa06240611f6c602812c226bed87{}) is called an unbound type parameter. Unbound type parameters have the following rules:

  • You cannot use the != and == operators because there is no guarantee of a concrete type parameter These operators are supported.

  • You can convert them to and from System.Object or explicitly convert them to any interface type.

  • They can be compared to null . When comparing an unbound parameter to null , the comparison will always return false if the type parameter is a value type.

Naked type constraints



Generic type parameters used as constraints are called naked Type constraints. Naked type constraints are useful when a member function that has its own type parameter needs to constrain that parameter to a type parameter of the containing type, as in the following example:

C

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

In the above example, T is a naked type constraint in the context of the Add method, and an unbound type constraint in the context of the List class certain type parameters.

Naked type constraints can also be used in generic class definitions. Note that the naked type constraint must also have been declared in angle brackets with any other type parameters:

C#
//naked type constraint
public class SampleClass<T, U, V> where T : V { }

The role of naked type constraints on generic classes is very limited, because the compiler assumes nothing more than a certain naked type constraint No assumptions are made other than derived from System.Object. You can use naked type constraints on a generic class when you want to enforce an inheritance relationship between two type parameters.

The above is the graphic and text details of where type constraints in C#. For more related content, please pay attention to the PHP Chinese website (www.php.cn)!


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn