tipos - usando generics c#
F#miembros restricciones+^ un byref parĂ¡metros (3)
Creo que también es un error, algo con restricciones de miembros y tipos byref. Puedo hacer una versión de reflexión un poco menos fea cambiando la firma de la restricción miembro:
let inline tryParse<''a when ''a : (static member TryParse : string -> ''a byref -> bool)> s =
let args = [| s ; null |]
if typeof<''a>
.GetMethod("TryParse", [| typeof<string>; typeof< ^a>.MakeByRefType() |])
.Invoke(null, args) = box true
then Some (args.[1] :?> ''a)
else None
Este es muy cercano:
let inline tryParse< ^a when ^a: (static member TryParse: string -> ^a byref -> bool)> s =
let mutable x = Unchecked.defaultof<''a>
if (^a: (static member TryParse: string -> ^a byref -> bool) (s, &x))
then Some x else None
pero obtengo un error FS0421: la dirección de la variable ''x'' no se puede usar en este momento cuando intento compilarla.
Después de jugar un poco con las restricciones de miembros F #, la función de escribir y escribir es la siguiente:
let inline parse< ^a when ^a : (static member Parse: string -> ^a) > s =
(^a: (static member Parse: string -> ^a) s)
Eso funciona perfectamente bien:
let xs = [ "123"; "456"; "999" ] |> List.map parse<int>
Estoy intentando escribir otras tryParse
, que usa el método estático TryParse
y ajusta el resultado del análisis en ''a option
tipo de ''a option
para una mejor compatibilidad en F #. Algo como esto no compila:
let inline tryParse s =
let mutable x = Unchecked.defaultof< ^a>
if (^a: (static member TryParse: string * ^a byref -> bool) (s, &x))
then Some x else None
El error es:
error FS0001: se esperaba que esta expresión tuviera el tipo byref <''a> pero aquí tiene el tipo '' a ref
F # ref
-cells tampoco funciona:
let inline tryParse s =
let x = ref Unchecked.defaultof< ^a>
if (^a: (static member TryParse: string * ^a byref -> bool) (s, x))
then Some x else None
¿Qué estoy haciendo mal?
Esto compila pero aún no funciona como se esperaba:
let inline tryParse< ^a when ^a: (static member TryParse: string -> ^a ref -> bool) > s =
let x = ref Unchecked.defaultof< ^a>
match (^a: (static member TryParse: string -> ^a ref -> bool ) (s, x)) with
| false -> None
| true -> Some(!x)
// returns [Some 0; Some 0; Some 0; null], so our tryParse is not retrieving the value from the ref
let xs = [ "1"; "456"; "999"; "a" ] |> List.map tryParse<int>
en este caso específico, en lugar de usar el reflejo, simplemente recrearía TryParse de Parse en f #
let inline tryParse< ^a when ^a: (static member Parse: string -> ^a) > s =
try
Some(^a: (static member Parse: string -> ^a) s)
with
| exn -> None
let xs = [ "1"; "456"; "999"; "a" ] |> List.map tryParse<int>
ACTUALIZAR
Esto parece estar arreglado en F # 3.0.
Respuesta anterior:
Estoy de acuerdo con el comentario de Stephen de que probablemente sea un error. Hay muchas limitaciones en los tipos byref, por lo que no me sorprende en particular que no jueguen bien con las restricciones de los miembros. Aquí hay una solución (fea) usando la reflexión:
type parseDel<''a> = delegate of string * ''a byref -> bool
type Parser< ^a when ^a : (static member TryParse: string * ^a byref -> bool)> private ()=
static let parser = System.Delegate.CreateDelegate(typeof<parseDel<''a>>, typeof<''a>.GetMethod("TryParse", [|typeof<string>; typeof<''a>.MakeByRefType()|])) :?> parseDel<''a>
static member inline ParseDel = parser
let inline tryParse (s:string) =
let mutable x = Unchecked.defaultof< ^a>
if Parser<_>.ParseDel.Invoke(s, &x) then
Some x
else None
let one : int option = tryParse "1"