2010-03-02 8 views
18

In C# posso fare:C# e F # casting - in particolare il 'come' parola chiave

var castValue = inputValue as Type1 

in F #, posso fare:

let staticValue = inputValue :> Type1 
let dynamicValue = inputValue :?> Type1 

Ma nessuno dei due è l'equivalente del C# come

Credo che ho bisogno di fare un'espressione partita per l'equivalente in F #

match inputValue with 
| :? Type1 as type1Value -> type1Value 
| _ -> null 

È corretto?

risposta

22

Per quanto ne so, F # non ha alcun operatore integrato equivalente a C# as quindi è necessario scrivere un'espressione più complicata. In alternativa al codice utilizzando match, si potrebbe anche usare if, perché l'operatore :? può essere utilizzato allo stesso modo come is in C#:

let res = if (inputValue :? Type1) then inputValue :?> Type1 else null 

Si può naturalmente scrivere una funzione per incapsulare questo comportamento (per la scrittura una semplice funzione generica che prende un Object e getta al parametro di tipo generico specificato):

let castAs<'T when 'T : null> (o:obj) = 
    match o with 
    | :? 'T as res -> res 
    | _ -> null 

Questa implementazione restituisce null, quindi richiede che il parametro tipo ha null come un puntello valore (in alternativa, è possibile utilizzare Unchecked.defaultof<'T>, che equivale a default(T) in C#). Ora puoi scrivere solo:

let res = castAs<Type1>(inputValue) 
+0

Questo funziona se il tipo è statico. Qualche idea su cosa fare se il tipo è definito in fase di runtime? Sto cercando un equivalente F # di http://stackoverflow.com/a/19068042/23059. –

6

È possibile creare il proprio operatore per fare questo. Questo è praticamente identico all'esempio di Tomas, ma mostra un modo leggermente diverso di chiamarlo. Ecco un esempio:

let (~~) (x:obj) = 
    match x with 
    | :? 't as t -> t //' 
    | _ -> null 

let o1 = "test" 
let o2 = 2 
let s1 = (~~o1 : string) // s1 = "test" 
let s2 = (~~o2 : string) // s2 = null 
10

Vorrei utilizzare un modello attivo. Qui è quello che uso io:

let (|As|_|) (p:'T) : 'U option = 
    let p = p :> obj 
    if p :? 'U then Some (p :?> 'U) else None 

Ecco un esempio dell'uso di As:

let handleType x = 
    match x with 
    | As (x:int) -> printfn "is integer: %d" x 
    | As (s:string) -> printfn "is string: %s" s 
    | _ -> printfn "Is neither integer nor string" 

// test 'handleType' 
handleType 1 
handleType "tahir" 
handleType 2. 
let stringAsObj = "tahir" :> obj 
handleType stringAsObj 
+2

Questo non è necessario ... come nota la domanda originale, la corrispondenza del modello F # ha questo integrato. Puoi '| | :? int come io -> i'. –

+0

è funzionalmente diverso dall'uso di '| :? 'come suggerisce @ DanFitch? – Maslow

+1

ha trovato una differenza molto utile. puoi eseguire il sub-matching post-cast senza una clausola when. 'function | As (Some true) ->() | _ ->() 'per esempio – Maslow