2009-05-20 12 views
15

Acabo de leer la información en this page, y si bien una nueva? se menciona al operador, no tengo muy claro cuál sería su uso.
¿Podría alguien dar una explicación rápida, publicar un código que no incluya cómo se usaría este operador y posiblemente mencionar un caso de uso?
Editar: esto es realmente incómodo, me he dado cuenta de que? el operador ya no se menciona en las notas de la versión de Don. ¿Alguna idea de por qué es eso?F # operator "?"

Respuesta

30

Hay dos nuevos operadores "especiales" en este comunicado de F #, y (<? -) (?). No están definidos, pero están disponibles para la sobrecarga, por lo que puede definirlos usted mismo. El bit especial es cómo tratan su segundo operando: requieren que sea un identificador de F # válido, pero lo pasan para funcionar implementando el operador como una cadena. En otras palabras:

a?b 

se Desazucarado a:

(?) a "b" 

y:

a?b <- c 

se Desazucarado a:

(?<-) a "b" c 

Una muy simple definición de los operadores podrían 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) 

Tenga en cuenta que dado que el tipo de cambio de la gettor es genérico, que tendrá que especificar que en el uso del sitio en la mayoría de los casos, es decir:

let name = foo?Name : string 

aunque todavía se puede cadena de guardia (?) (desde primer argumento de (?) es también genérico):

let len = foo?Name?Length : int 

Otro, más interesante, es la implementación de volver a utilizar el método proporcionado por CallByName 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 

La ventaja de esto es que va a manejar tanto las propiedades y campos correctamente, trabajar con objetos IDispatch COM, etc.

+1

Como nota al margen, aparentemente, F # PowerPack incluye una implementación predeterminada razonable. –

4

Parece el "?" operador se relaciona con el Dynamic Language Runtime (DLR). Es decir, lo usa cuando desea enlazar a un miembro de objeto (método, propiedad) en tiempo de ejecución, en lugar de en tiempo de compilación.

Es gracioso porque esperaba que así fuera también la invocación dinámica de miembros en C#. Por desgracia, C# expone esta funcionalidad a través de un tipo "pseudo" ("dinámico" IIRC). En mi opinión, esto hace que el código sea algo menos claro (porque debe rastrear la declaración de la variable para saber si la llamada se enlazó anticipadamente o se enlazó posteriormente).

No sé la sintaxis exacta, pero si tuviera que adivinar, reemplaza o aumenta el "." (punto) operador. Como en:

let x = foo?Bar() 

o tal vez:

let x = foo.?Bar() 
+1

"porque debe rastrear la declaración de la variable para saber si la llamada se enlaza de manera anticipada o atrasada" ... No es necesario realizar un seguimiento muy lejano. dynamic debe ser una variable local y no puede ser un miembro de tipo; si tiene que desplazarse muy lejos para averiguar si una variable es dinámica o no, es probable que necesite refactorizar. Además, el IDE con mucho gusto le dirá el tipo si coloca el cursor sobre el nombre de una variable ... – Randolpho

+2

Puntos buenos. Por lo que vale, hay otra razón por la que preferiría un operador de "llamada de última hora" sobre la implementación de tipo "dinámico": dado que es posible conectar el DLR mediante la implementación de una interfaz, puedo imaginar un escenario donde le gustaría hacer llamadas de límite temprano y llamadas de último momento con la misma referencia. –

+0

Por curiosidad, ¿cuál debería ser el tipo de foo y por qué querría hacer eso en lugar de foo.Bar()? Además, ¿no puedo ya lograr el mismo resultado a través de la reflexión? – em70

1

Hay un módulo de FSharp.Interop.Dynamic, en Nuget que implementa el operador dinámico utilizando el DLR.

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

es de código abierto, la licencia de Apache, se puede ver en la implementation e incluye prueba de unidad example cases.