Partilhar via


Restrições

Este tópico descreve as restrições que você pode aplicar a parâmetros de tipo genéricos para especificar os requisitos para um argumento de tipo em um tipo ou função genéricos.

Sintaxe

type-parameter-list when constraint1 [ and constraint2]

Comentários

Há várias restrições diferentes que você pode aplicar para limitar os tipos que podem ser usados em um tipo genérico. A tabela a seguir lista e descreve essas restrições.

Restrição Sintaxe Descrição
Restrição de tipo parâmetro de tipo :>tipo O tipo fornecido deve ser igual ou derivado do tipo especificado ou, se o tipo for uma interface, o tipo fornecido deve implementar a interface.
Restrição nula parâmetro de tipo : nulo O tipo fornecido deve suportar o valor nulo. Isso inclui todos os tipos de objeto .NET, mas não os tipos de lista, tupla, função, classe, registro ou união F#.
Restrição não nula parâmetro de tipo : não nulo O tipo fornecido não deve suportar o valor nulo. Isso não permite tanto null tipos anotados quanto tipos que têm null como seu valor de representação (como o option type ou tipos definidos com o atributo AllowNullLiteral). Essa restrição genérica permite tipos de valor, uma vez que eles nunca podem ser nulos.
Restrição explícita de membro [(]parâmetro-tipo [ou ... ou parâmetro-tipo)] : (assinatura de membro) Pelo menos um dos argumentos de tipo fornecidos deve ter um membro que tenha a assinatura especificada; não se destina a uso comum. Os membros devem ser explicitamente definidos no tipo ou como parte de uma extensão implícita de tipo para serem destinos válidos para uma restrição explícita de membro.
Restrição do construtor parâmetro-tipo : ( novo : unidade -> 'a ) O tipo fornecido deve ter um construtor sem parâmetros.
Restrição de tipo de valor parâmetro de tipo : struct O tipo fornecido deve ser um tipo de valor .NET.
Restrição de tipo de referência parâmetro-tipo : não estrutura O tipo fornecido deve ser um tipo de referência .NET.
Restrição de tipo de enumeração parâmetro-tipo : enum<tipo subjacente> O tipo fornecido deve ser um tipo enumerado que tenha o tipo subjacente especificado; não se destina a uso comum.
Restrições de Delegação type-parameter : delegar<tuple-parameter-typereturn-type> O tipo fornecido deve ser um tipo delegado que tenha os argumentos especificados e o valor de retorno; não se destina a uso comum.
Restrição de comparação tipo de parâmetro : comparação O tipo fornecido deve suportar a comparação.
Restrição de igualdade parâmetro-tipo : igualdade O tipo fornecido deve apoiar a igualdade.
Restrição não gerenciada parâmetro de tipo : não gerenciado O tipo fornecido deve ser um tipo não gerenciado. Tipos não gerenciados são certos tipos primitivos (sbyte, byte, char, nativeint, unativeint, float32, float, int16, uint16, int32, uint32, int64, uint64ou decimal), tipos de enumeração, nativeptr<_>, ou uma estrutura não genérica cujos campos são todos tipos não gerenciados.

Você precisa adicionar uma restrição quando seu código precisa usar um recurso que está disponível no tipo de restrição, mas não nos tipos em geral. Por exemplo, se você usar a restrição de tipo para especificar um tipo de classe, poderá usar qualquer um dos métodos dessa classe na função ou tipo genérico.

Especificar restrições às vezes é necessário ao escrever parâmetros de tipo explicitamente, porque sem uma restrição, o compilador não tem como verificar se os recursos que você está usando estarão disponíveis em qualquer tipo que possa ser fornecido em tempo de execução para o parâmetro type.

As restrições mais comuns que você usa no código F# são restrições de tipo que especificam classes base ou interfaces. As outras restrições são usadas pela biblioteca F# para implementar determinadas funcionalidades, como a restrição de membro explícito, que é usada para implementar a sobrecarga do operador para operadores aritméticos, ou são fornecidas principalmente porque o F# suporta o conjunto completo de restrições que é suportado pelo Common Language Runtime.

Durante o processo de inferência de tipo, algumas restrições são inferidas automaticamente pelo compilador. Por exemplo, se você usar o operador + em uma função, o compilador inferirá uma restrição de membro explícita em tipos de variáveis que são usados na expressão.

O código a seguir ilustra algumas declarações de restrição:

// Base Type Constraint
type Class1<'T when 'T :> System.Exception> =
    class end

// Interface Type Constraint
type Class2<'T when 'T :> System.IComparable> =
    class end

// Null constraint
type Class3<'T when 'T : null> =
    class end

// Not Null constraint
type Class4<'T when 'T : not null> =
    class end

// Member constraint with instance member
type Class5<'T when 'T : (member Method1 : 'T -> int)> =
    class end

// Member constraint with property
type Class6<'T when 'T : (member Property1 : int)> =
    class end

// Constructor constraint
type Class7<'T when 'T : (new : unit -> 'T)>() =
    member val Field = new 'T()

// Reference type constraint
type Class8<'T when 'T : not struct> =
    class end

// Enumeration constraint with underlying value specified
type Class9<'T when 'T : enum<uint32>> =
    class end

// 'T must implement IComparable, or be an array type with comparable
// elements, or be System.IntPtr or System.UIntPtr. Also, 'T must not have
// the NoComparison attribute.
type Class10<'T when 'T : comparison> =
    class end

// 'T must support equality. This is true for any type that does not
// have the NoEquality attribute.
type Class11<'T when 'T : equality> =
    class end

type Class12<'T when 'T : delegate<obj * System.EventArgs, unit>> =
    class end

type Class13<'T when 'T : unmanaged> =
    class end

// Member constraints with two type parameters
// Most often used with static type parameters in inline functions
let inline add(value1 : ^T when ^T : (static member (+) : ^T * ^T -> ^T), value2: ^T) =
    value1 + value2

// ^T and ^U must support operator +
let inline heterogenousAdd(value1 : ^T when (^T or ^U) : (static member (+) : ^T * ^U -> ^T), value2 : ^U) =
    value1 + value2

// If there are multiple constraints, use the and keyword to separate them.
type Class14<'T,'U when 'T : equality and 'U : equality> =
    class end

Ver também