Vincoli (F#)

In questo argomento vengono descritti i vincoli che è possibile applicare ai parametri di tipo generico per specificare i requisiti per un argomento di tipo in una funzione o un tipo generico.

type-parameter-list when constraint1 [ and constraint2]

Note

Sono disponibili diversi vincoli che è possibile applicare per limitare i tipi che possono essere utilizzati in un tipo generico. Nella tabella seguente sono elencati e descritti questi vincoli.

Vincolo

Sintassi

Descrizione

Vincolo di tipo

type-parameter :> type

Il tipo fornito deve essere uguale al o derivato dal tipo specificato oppure, se il tipo è un'interfaccia, il tipo fornito deve implementare l'interfaccia.

Vincolo Null

type-parameter : null

Il tipo fornito deve supportare il valore letterale Null. Sono inclusi tutti i tipi di oggetti .NET ma non i tipi di elenco, tupla, funzione, classe, record o unione F#.

Vincolo di membro esplicito

[(]type-parameter [or ... o type-parameter)] : (member-signature)

Almeno uno degli argomenti di tipo forniti deve disporre di un membro con la firma specificata. Non destinato all'utilizzo comune.

Vincolo del costruttore

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

Il tipo fornito deve disporre di un costruttore predefinito.

Vincolo del tipo di valore

: struct

Il tipo fornito deve essere un tipo di valore .NET.

Vincolo del tipo di riferimento

: not struct

Il tipo fornito deve essere un tipo di riferimento .NET.

Vincolo del tipo di enumerazione

: enum <underlying-type>

Il tipo fornito deve essere un tipo enumerato che dispone del tipo sottostante specificato. Non destinato all'utilizzo comune.

Vincolo di delegato

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

Il tipo fornito deve essere un tipo delegato che dispone degli argomenti specificati e di un valore restituito. Non destinato all'utilizzo comune.

Vincolo di confronto

: comparison

Il tipo fornito deve supportare il confronto.

Vincolo di uguaglianza

: equality

Il tipo fornito deve supportare l'uguaglianza.

Vincolo non gestito

: unmanaged

Il tipo fornito deve essere un tipo non gestito. I tipi non gestiti sono determinati tipi primitivi (sbyte, byte, char, nativeint, unativeint, float32, float, int16, uint16, int32, uint32, int64, uint64 o decimal), tipi di enumerazione, nativeptr<_> o una struttura non generica i cui campi sono tutti tipi non gestiti.

È necessario aggiungere un vincolo quando il codice deve utilizzare una funzionalità disponibile nel tipo di vincolo ma non nei tipi in generale. Se, ad esempio, si utilizza il vincolo di tipo per specificare un tipo di classe, è possibile utilizzare uno qualsiasi dei metodi della classe nella funzione o nel tipo generico.

È a volte necessario specificare i vincoli in fase di scrittura esplicita dei parametri di tipo, in quanto senza un vincolo il compilatore non può verificare che le funzionalità che si stanno utilizzando saranno disponibili in qualsiasi tipo che potrebbe venire fornito al runtime per il parametro di tipo.

I vincoli più comuni utilizzati nel codice F# sono i vincoli di tipo che specificano interfacce o classi di base. Gli altri vincoli vengono utilizzati dalla libreria F# per implementare determinate funzionalità, ad esempio il vincolo di membro esplicito, utilizzato per implementare l'overload degli operatori per gli operatori aritmetici, oppure vengono forniti principalmente perché F# supporta il set completo di vincoli supportati da Common Language Runtime.

Durante il processo di inferenza del tipi, alcuni vincoli vengono derivati automaticamente dal compilatore. Se, ad esempio, si utilizza l'operatore + in una funzione, il compilatore deriva un vincolo di membro esplicito nei tipi di variabile utilizzati nell'espressione.

Il codice seguente illustra alcune dichiarazioni del vincolo.

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

Vedere anche

Riferimenti

Generics (F#)

Vincoli (F#)