Per visualizzare l'articolo in inglese, selezionare la casella di controllo Inglese. È possibile anche visualizzare il testo inglese in una finestra popup posizionando il puntatore del mouse sopra il testo.
Traduzione
Inglese

Cast e conversioni (F#)

In questo argomento viene descritto il supporto per la conversione dei tipi in F#.

F# fornisce operatori di conversione per le conversioni aritmetiche tra diversi tipi primitivi, ad esempio tipi Integer e a virgola mobile. Gli operatori di conversione di valori integrali e caratteri dispongono di forme verificate e non verificate, mentre gli operatori a virgola mobile e l'operatore di conversione enum no. Le forme non verificate sono definite in Microsoft.FSharp.Core.Operators, mentre quelle verificate in Microsoft.FSharp.Core.Operators.Checked. Le forme verificate consentono di controllare se si verifica un overflow e generano un'eccezione in fase di esecuzione se il valore risultante supera i limiti del tipo di destinazione.

Ognuno di questi operatori ha lo stesso nome del tipo di destinazione. Nel codice seguente, in cui i tipi sono annotati in modo esplicito, byte appare, ad esempio, con due significati diversi. La prima occorrenza corrisponde al tipo e la seconda all'operatore di conversione.

let x : int = 5

let b : byte = byte x

Nella tabella seguente vengono mostrati operatori di conversione definiti in F#.

Operatore

Descrizione

byte

Conversione in byte, un tipo senza segno a 8 bit.

sbyte

Conversione in byte con segno.

int16

Conversione in Signed Integer a 16 bit.

uint16

Conversione in Unsigned Integer a 16 bit.

int32, int

Conversione in Signed Integer a 32 bit.

uint32

Conversione in Unsigned Integer a 32 bit.

int64

Conversione in Signed Integer a 64 bit.

uint64

Conversione in Unsigned Integer a 64 bit.

nativeint

Conversione in intero nativo.

unativeint

Conversione in intero nativo senza segno.

float, double

Conversione in un numero a virgola mobile IEEE e precisione doppia a 64 bit.

float32, single

Conversione in un numero a virgola mobile IEEE e precisione singola a 32 bit.

decimal

Conversione in System.Decimal.

char

Conversione in System.Char, un carattere Unicode.

enum

Conversione in un tipo enumerato.

Oltre ai tipi primitivi incorporati, è possibile utilizzare questi operatori con tipi che implementano op_Explicit o i metodi op_Implicit con le firme appropriate. L'operatore di conversione int è ad esempio compatibile con qualsiasi tipo che fornisce un metodo op_Explicit statico che utilizza il tipo come parametro e restituisce int. Come eccezione speciale alla regola generale che prevede che i metodi non possano essere sottoposti a overload in base al tipo restituito, è possibile eseguire questa operazione per op_Explicit e op_Implicit.

L'operatore enum è un operatore generico che accetta un parametro che rappresenta il tipo di elemento enum in cui eseguire la conversione. Quando viene eseguita la conversione in un tipo enumerato, tramite l'inferenza del tipo viene eseguito un tentativo di determinare il tipo di elemento enum in cui si desidera eseguire la conversione. Nell'esempio seguente la variabile col1 non è annotata in modo esplicito, ma il relativo tipo viene derivato dal test di uguaglianza successivo. Il compilatore può pertanto dedurre che si sta eseguendo la conversione in un'enumerazione Color. In alternativa, è possibile fornire un'annotazione del tipo, come nel caso di col2 nell'esempio seguente.

type Color =
    | Red = 1
    | Green = 2
    | Blue = 3

// The target type of the conversion is determined by type inference. 
let col1 = enum 1
// The target type is supplied by a type annotation. 
let col2 : Color = enum 2 
do 
    if (col1 = Color.Red) then
       printfn "Red"

È anche possibile specificare il tipo di enumerazione di destinazione in modo esplicito come parametro di tipo, come nel codice seguente:

let col3 = enum<Color> 3

Si noti che i cast di enumerazione sono disponibili solo se il tipo sottostante dell' enumerazione è compatibile con il tipo convertito. In il codice seguente, la conversione non riesce alla compilazione a causa della mancata corrispondenza tra int32 e uint32.

// Error: types are incompatible
let col4 : Color = enum 2u

Per ulteriori informazioni, vedere Enumerazioni (F#).

La conversione tra tipi in una gerarchia di oggetti è fondamentale per la programmazione orientata a oggetti. Vi sono due tipi di base di conversioni: il cast verso l'alto (upcast) e il cast verso il basso (downcast). L'upcast in una gerarchia indica il cast da un riferimento a un oggetto derivato a un riferimento a un oggetto di base. Tale tipo di cast funziona a condizione che la classe di base si trovi nella gerarchia di ereditarietà della classe derivata. Il downcast in una gerarchia, da un riferimento a un oggetto di base a un riferimento a un oggetto derivato, ha esito positivo solo se l'oggetto è effettivamente un'istanza del tipo di destinazione (derivato) corretto o un tipo derivato dal tipo di destinazione.

In F# sono disponibili operatori per questi tipi di conversioni. L'operatore :> consente di eseguire l'upcast nella gerarchia, mentre l'operatore :?> consente di eseguire il downcast.

In numerosi linguaggi orientati a oggetti, l'upcast è implicito, mentre in F# le regole sono leggermente diverse. L'upcast viene eseguito automaticamente quando si passano argomenti ai metodi in un tipo di oggetto. Per le funzioni con associazione let in un modulo, tuttavia, l'upcast non è automatico a meno che il tipo di parametro non venga dichiarato come tipo flessibile. Per ulteriori informazioni, vedere Tipi flessibili (F#).

L'operatore :> consente di eseguire un cast statico, che significa che la riuscita del cast viene determinata in fase di compilazione. Se un cast in cui viene utilizzato l'operatore :> viene compilato correttamente, si tratta di un cast valido e non è possibile che si verifichi un errore in fase di esecuzione.

È anche possibile utilizzare l'operatore upcast per eseguire una conversione di questo tipo. Nell'espressione seguente viene specificata una conversione verso l'alto nella gerarchia.

upcast expression

Quando si utilizza l'operatore di upcast, il compilatore tenta di dedurre il tipo che si sta convertendo dal contesto. Se il compilatore non è in grado di determinare il tipo di destinazione, viene segnalato un errore.

L'operatore :?> consente di eseguire un cast dinamico, che significa che la riuscita del cast viene determinata in fase di esecuzione. Un cast in cui viene utilizzato l'operatore :?> non viene controllato in fase di compilazione, ma in fase di esecuzione viene effettuato un tentativo di eseguire il cast al tipo specificato. Se l'oggetto è compatibile con il tipo di destinazione, il cast ha esito positivo. Se l'oggetto non è compatibile con il tipo di destinazione, il runtime genera un evento InvalidCastException.

È anche possibile utilizzare l'operatore downcast per eseguire una conversione dinamica del tipo. Nell'espressione seguente viene specificata una conversione verso il basso della gerarchia in un tipo derivato dal contesto del programma.

downcast expression

Come per l'operatore di upcast, se il compilatore non è in grado di dedurre un tipo di destinazione specifico dal contesto, viene segnalato un errore.

Nel codice seguente viene illustrato l'utilizzo degli operatori :> e :?>. Nel codice viene illustrato che è preferibile utilizzare l'operatore :?> quando si sa che la conversione avrà esito positivo, in quanto, in caso di esito negativo, viene generato un evento InvalidCastException. Se non si è certi che una conversione avrà esito positivo, è consigliabile un test del tipo in cui viene utilizzata l'espressione match, in quanto consente di evitare il sovraccarico dovuto alla generazione di un'eccezione.

type Base1() =
    abstract member F : unit -> unit
    default u.F() =
     printfn "F Base1" 

type Derived1() =
    inherit Base1()
    override u.F() =
      printfn "F Derived1" 


let d1 : Derived1 = Derived1()

// Upcast to Base1. 
let base1 = d1 :> Base1

// This might throw an exception, unless 
// you are sure that base1 is really a Derived1 object, as 
// is the case here. 
let derived1 = base1 :?> Derived1

// If you cannot be sure that b1 is a Derived1 object, 
// use a type test, as follows: 
let downcastBase1 (b1 : Base1) =
   match b1 with
   | :? Derived1 as derived1 -> derived1.F()
   | _ -> ()

downcastBase1 base1

Poiché gli operatori generici downcast e upcast si basano sull'inferenza del tipo per determinare l'argomento e il tipo restituito, nel codice precedente è possibile sostituire

let base1 = d1 :> Base1

con

base1 = upcast d1

Nel codice precedente il tipo di argomento e i tipi restituiti sono, rispettivamente, Derived1 e Base1.

Per ulteriori informazioni sui test del tipo, vedere Espressioni match (F#).

Aggiunte alla community

Mostra: