Compartilhar via


Restrições em parâmetros de tipo (Guia de programação C#)

Quando você define uma classe genérico, você pode aplicar restrições para os tipos de tipos que código de cliente pode usar para argumentos Tipo quando ele instancia sua classe.Se o código do cliente tenta instanciar sua classe usando um tipo que não é permitido por uma restrição, o resultado é um erro em time de compilar.Essas restrições são chamadas restrições.Restrições são especificadas usando o where palavra-chave contextual. A tabela a seguir lista os seis tipos de restrições :

Restrição

Descrição

where : struct

O argumento Tipo deve ser um tipo de valor.Qualquer tipo de valor, exceto Nullable pode ser especificado. Consulte Usando Nullable Types (guia de programação translation from VPE for Csharp) para obter mais informações.

where : classe

O argumento de tipo deve ser um tipo de referência; isso se aplica também a qualquer classe, interface, delegado ou tipo de matriz.

where : New() T

O argumento Tipo deve ter um construtor sem-parâmetros público.Quando usado em conjunto com outras restrições, o new() restrição deve ser especificada pela última vez.

where : <base class name>

O argumento Tipo deve ser ou derivar de classe base especificada.

where : <interface name>

O argumento Tipo deve ser ou implementam a interface especificada.Várias restrições interface podem ser especificadas.A interface restrições também pode ser genérica.

where : U

O argumento de tipo fornecido para T deve ser ou derivar de argumento fornecido para u.Isso é chamado de uma restrição de tipo nua.

Por que usar restrições

Se você quiser examinar um item em uma lista genérica para determinar se é válido ou para compará-lo com Outros item, o compilador deve ter alguns garante que o operador ou a telefonar do método terá suporte por qualquer argumento de tipo que pode ser especificado pelo código do cliente.ESTA GARANTIA é obtida ao aplicar uma ou mais restrições para a definição de classe genérico.Por exemplo, a restrição classe base informa o compilador que somente objetos desse tipo ou derivado desse tipo será usado como argumentos Tipo.Depois que o compilador tiver essa garantia, ela pode permitir que os métodos desse tipo a ser chamado na classe genérica.Restrições são aplicadas usando a palavra-chave contextual where. O exemplo de código a seguir demonstra a funcionalidade que podemos adicionar o GenericList<T> (na classe Introdução ao Generics (guia de programação C#)), aplicando uma restrição de classe base.

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

A restrição permite que a classe genérica usar o Employee.Name propriedade porque todos os itens do tipo T têm a garantia de ser um Employee objeto que herda de ou Employee.

Várias restrições podem ser aplicadas para o mesmo parâmetro, tipo e as restrições próprios podem ser tipos genéricos, da seguinte forma:

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

Restringindo o parâmetro de tipo, você aumentar o número de operações permitidas e chamadas de método aos quais o tipo de restrições e todos os tipos na sua hierarquia de herança.Portanto, quando você cria classes genéricas ou métodos, se você se executar qualquer operação nos membros genéricos além da atribuição simples ou chamar quaisquer métodos não suportados pelo System.Object, você terá que aplicar restrições ao parâmetro de tipo.

Ao aplicar o where T : class restrição, evitar o == e != operadores no parâmetro de tipo porque esses operadores serão teste para identidade de referência único, não para o valor de igualdade. Esse é o caso mesmo se esses operadores são sobrecarregados em um tipo que é usado sistema autônomo um argumento.O código a seguir ilustra este ponto; o resultado é false mesmo que o String sobrecargas de classe a == operador.

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

A razão para esse comportamento é que, ao tempo de compilação, o compilador somente sabe que T é um tipo de referência, e portanto deve utilizar os operadores padrão que são válidos para todos os tipos de referência.Se você deve testar a igualdade do valor, a maneira recomendada é também se aplicam a where T : IComparable<T> restrição e implementar que interface em qualquer classe que será usado para construir a classe genérica.

A restrição de vários parâmetros

Você pode aplicar restrições para vários parâmetros e várias restrições de um único parâmetro sistema autônomo mostrado no exemplo a seguir:

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

Unbounded parâmetros tipo

Parâmetros tipo que têm sem restrições, como T na classe SampleClass<T>{} pública, são chamados parâmetros tipo unbounded.Parâmetros tipo unbounded ter as seguintes regras:

  • The != e == operadores não podem ser usados porque não há nenhuma garantia de que o argumento de tipo concreto será compatível com esses operadores.

  • Pode ser convertidos para / de System.Object ou explicitamente convertido para qualquer tipo de interface.

  • Você pode comparar e nulo.Se um parâmetro não vinculado é comparado com null, a comparação sempre retornará false se o argumento de tipo é um tipo de valor.

Naked restrições tipo

Quando um parâmetro tipo genérico é usado como uma restrição, ela é chamada uma restrição tipo naked.Restrições de tipo nua são úteis quando tem uma função de membro com seu próprio tipo de parâmetro restringir esse parâmetro para o parâmetro de tipo do tipo recipiente, conforme mostrado no exemplo a seguir:

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

No exemplo anterior, T é uma restrição de tipo nua no contexto das Add método e um parâmetro de tipo não vinculado no contexto das List classe.

Restrições naked tipo podem ser usadas em definições de classe genérico.Observe que a restrição de tipo nua também deve ter sido declarada nos colchetes junto com quaisquer outros parâmetros de tipo:

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

A utilidade de restrições de tipo nua com classes genéricas é muito limitada porque o compilador pode assumir nada sobre uma restrição de tipo nua, exceto pelo fato de que ele deriva de System.Object. Use restrições nua tipo em classes genéricas em cenários em que você deseja impor um Relação de herança entre dois parâmetros de tipo.

Consulte também

Conceitos

Guia de Programação C#

Referência

Introdução ao Generics (guia de programação C#)

Nova restrição (referência C#)

System.Collections.Generic

Date

History

Motivo

Julho de 2008

Adicionado o parágrafo em várias restrições.

Correção de bug do conteúdo.