2009-05-20 16 views
15

Ho appena letto le informazioni su this page e mentre una nuova? operatore è menzionato, non mi è chiaro quale sarebbe il suo utilizzo.
Qualcuno potrebbe fornire una spiegazione rapida, pubblicare un codice tagliato di come sarebbe utilizzato questo operatore e possibilmente menzionare un caso d'uso?
Modifica: questo è davvero imbarazzante, ho notato che il? l'operatore non è più menzionato nelle note di rilascio di Don. Qualche idea del perché è così?Operatore F # "?"

risposta

30

Ci sono due nuovi operatori "speciali" in questo # versione F, e (<? -) (?). Non sono definiti, ma sono disponibili per il sovraccarico, quindi è possibile definirli da soli. Il bit speciale è il modo in cui trattano il loro 2 ° operando: richiedono che sia un identificatore F # valido, ma lo passano per funzionare implementando l'operatore come una stringa. In altre parole:

a?b 

è Dezuccherato a:

(?) a "b" 

e:

a?b <- c 

è Dezuccherato a:

(?<-) a "b" c 

Una definizione molto semplice di tali operatori potrebbero be:

let inline (?) (obj: 'a) (propName: string) : 'b = 
    let propInfo = typeof<'a>.GetProperty(propName) 
    propInfo.GetValue(obj, null) :?> 'b 

let inline (?<-) (obj: 'a) (propName: string) (value: 'b) = 
    let propInfo = typeof<'a>.GetProperty(propName) 
    propInfo.SetValue(obj, value, null) 

Nota che, poiché il tipo di ritorno per la gettor è generico, si dovrà specificare che ad un uso sito in maggior parte dei casi, vale a dire:

let name = foo?Name : string 

anche se è ancora a catena-call (?) (dal primo argomento (?) è anche generico):

let len = foo?Name?Length : int 

altro, più interessante, l'attuazione è riutilizzare il metodo CallByName fornito da VB:

open Microsoft.VisualBasic  

let inline (?) (obj: 'a) (propName: string) : 'b = 
    Interaction.CallByName(obj, propName, CallType.Get, null) :?> 'b //' 

let inline (?<-) (obj: 'a) (propName: string) (value: 'b) = 
    Interaction.CallByName(obj, propName, CallType.Set, [| (value :> obj) |]) 
    |> ignore 

Il vantaggio di questo è che tratterà sia le proprietà ei campi correttamente, lavorare con gli oggetti IDispatch COM, ecc

+1

Come nota a margine, apparentemente, F # PowerPack include un'implementazione predefinita ragionevole. –

4

Sembra il "?" l'operatore si riferisce al Dynamic Language Runtime (DLR). Cioè, lo si usa quando si desidera associare a un membro dell'oggetto (metodo, proprietà) in fase di esecuzione piuttosto che in fase di compilazione.

È divertente perché speravo che questo sarebbe stato anche il modo in cui l'invocazione dinamica dei membri funzionava anche in C#. Purtroppo, C# espone questa funzionalità tramite un tipo "pseudo" (IIRC "dinamico"). A mio parere, questo rende il codice un po 'meno chiaro (perché devi rintracciare la dichiarazione della variabile per sapere se la chiamata è vincolata in anticipo o in ritardo).

Non conosco la sintassi esatta, ma se dovessi indovinare, sostituisce o aumenta "." operatore (punto). Come in:

let x = foo?Bar() 

o forse:

let x = foo.?Bar() 
+1

"perché devi rintracciare la dichiarazione della variabile per sapere se la chiamata è vincolata in anticipo o in ritardo" ... Non è necessario tracciare molto lontano. dynamic deve essere una variabile locale e non può essere un membro di tipo; se devi scorrere molto lontano per scoprire se una variabile è o meno dinamica, è probabile che tu abbia bisogno di un refactoring. Inoltre l'IDE ti dirà volentieri il tipo se passi il mouse sopra il nome di una variabile ... – Randolpho

+2

Buoni punti. Per quello che vale, c'è un'altra ragione per cui preferirei un operatore di "chiamata tardiva" rispetto all'implementazione di tipo "dinamico": Dato che è possibile collegare il DLR implementando un'interfaccia, posso immaginare uno scenario in cui ti piacerebbe fare le chiamate precoci e le chiamate in ritardo sullo stesso riferimento. –

+0

Per curiosità quale dovrebbe essere il tipo di foo e perché dovrei farlo al posto di foo.Bar()? Inoltre, non riesco già a ottenere lo stesso risultato tramite la riflessione? – em70

1

C'è un modulo FSharp.Interop.Dynamic, su NuGet che implementa l'operatore dinamico utilizzando il dlr.

let ex1 = ExpandoObject() in 
ex1?Test<-"Hi"; 
ex1?Test |> should equal "Hi"; 

è open source, licenza Apache, si può guardare la implementation e comprende test di unità example cases.