Compartir a través de


Restricciones (F#)

En este tema se describen las restricciones que se pueden aplicar a los parámetros de tipo genérico a fin de especificar los requisitos para un argumento de tipo en un tipo genérico o una función genérica.

type-parameter-list when constraint1 [ and constraint2]

Comentarios

Hay varias restricciones diferentes que se pueden aplicar para limitar los tipos que se pueden utilizar en un tipo genérico. En la tabla siguiente se muestran y describen estas restricciones.

Restricción

Sintaxis

Descripción

Restricción de tipo

type-parameter :> type

El tipo proporcionado debe ser igual que el tipo especificado o derivarse de él; o bien, si el tipo es una interfaz, el tipo proporcionado debe implementar la interfaz.

Restricción de NULL

type-parameter : null

El tipo proporcionado debe admitir el literal NULL. Esto incluye todos los tipos de objeto de .NET, pero no los tipos de lista, tupla, función, clase, registro o unión de F#.

Restricción de miembro explícita

[] (type-parameter [o… o type-parameter)] : (member-signature)

Por lo menos uno de los argumentos de tipo proporcionados debe tener un miembro que tenga la signatura especificada; no se ha diseñado para uso frecuente.

Restricción de constructor

type-parameter : ( new : unit -> 'a )

El tipo proporcionado debe tener un constructor predeterminado.

Restricción de tipo de valor

: struct

El tipo proporcionado debe ser un tipo de valor de .NET.

Restricción de tipo de referencia

: not struct

El tipo proporcionado debe ser un tipo de referencia de .NET.

Restricción de tipo de enumeración

: enum<underlying-type>

El tipo proporcionado debe ser un tipo enumerado que tiene el tipo subyacente especificado; no se ha diseñado para uso frecuente.

Restricción de delegado

: delegate<tuple-parameter-type, return-type>

El tipo proporcionado debe ser un tipo de delegado que tiene los argumentos y el valor devuelto especificados; no se ha diseñado para uso frecuente.

Restricción de comparación

: comparison

El tipo proporcionado debe admitir la comparación.

Restricción de igualdad

: equality

El tipo proporcionado debe admitir la igualdad.

Restricción de no administrado

: unmanaged

El tipo proporcionado debe ser un tipo no administrado. Entre los tipos no administrados se encuentran algunos tipos primitivos (sbyte, byte, char, nativeint, unativeint, float32, float, int16, uint16, int32, uint32, int64, uint64, o decimal), tipos de enumeración, nativeptr<_>, o una estructura no genérica cuyos campos son tipos no administrados.

Se debe agregar una restricción cuando el código tiene que utilizar una característica que está disponible en el tipo de restricción pero no en los tipos en general. Por ejemplo, si se utiliza la restricción de tipo para especificar un tipo de clase, se puede utilizar cualquiera de los métodos de esa clase en la función o el tipo genérico.

A veces, al escribir explícitamente parámetros de tipo, es necesario especificar restricciones ya que, sin ellas, el compilador no puede comprobar si las características que se utilizan estarán disponibles en los tipos que se proporcionen para el parámetro de tipo en tiempo de ejecución.

Las restricciones más comunes que se utilizan en el código de F# son las restricciones de tipo que especifican clases base o interfaces. Las demás restricciones se utilizan en la biblioteca de F# para implementar determinadas funcionalidades (como la restricción de miembro explícita, que se utiliza para implementar la sobrecarga de operadores para los operadores aritméticos), o se proporcionan principalmente porque F# admite todas las restricciones que Common Language Runtime admite.

Durante el proceso de inferencia de tipos, el compilador realiza automáticamente la inferencia de tipos de algunas restricciones. Por ejemplo, si se utiliza el operador + en una función, la inferencia de tipos del compilador da como resultado una restricción de miembro explícita para los tipos variables que se utilizan en la expresión.

El siguiente código muestra algunas declaraciones de restricción.

// 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

// Member constraint with static member
type Class4<'T when 'T : (static member staticMethod1 : unit -> 'T) > =
    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

Vea también

Referencia

Genéricos (F#)

Restricciones (F#)