Zoeken…


Robuuste reflectie met behulp van F # citaten

Reflectie is nuttig maar fragiel. Overweeg dit:

let mi  = typeof<System.String>.GetMethod "StartsWith"

De problemen met dit soort code zijn:

  1. De code werkt niet omdat er verschillende overbelastingen van String.StartsWith
  2. Zelfs als er op dit moment geen overbelastingen zouden zijn, zouden latere versies van de bibliotheek een overbelasting kunnen toevoegen die een runtime-crash veroorzaakt
  3. Refactoring tools zoals Rename methods worden verbroken door reflectie.

Dit betekent dat we runtime-crashes krijgen voor iets waarvan bekend is dat het compileertijd is. Dat lijkt suboptimaal.

Met behulp van F# citaten is het mogelijk om alle bovenstaande problemen te voorkomen. We definiëren enkele helpfuncties:

open FSharp.Quotations
open System.Reflection

let getConstructorInfo (e : Expr<'T>) : ConstructorInfo =
  match e with
  | Patterns.NewObject (ci, _) -> ci
  | _ -> failwithf "Expression has the wrong shape, expected NewObject (_, _) instead got: %A" e


let getMethodInfo (e : Expr<'T>) : MethodInfo =
  match e with
  | Patterns.Call (_, mi, _) -> mi
  | _ -> failwithf "Expression has the wrong shape, expected Call (_, _, _) instead got: %A" e

We gebruiken de volgende functies:

printfn "%A" <| getMethodInfo <@ "".StartsWith "" @>
printfn "%A" <| getMethodInfo <@ List.singleton 1 @>
printfn "%A" <| getConstructorInfo <@ System.String [||] @>

Dit drukt af:

Boolean StartsWith(System.String)
Void .ctor(Char[])
Microsoft.FSharp.Collections.FSharpList`1[System.Int32] Singleton[Int32](Int32)

<@ ... @> betekent dat in plaats van de uitdrukking in F# , een uitdrukkingsboom wordt gegenereerd die de uitdrukking vertegenwoordigt. <@ "".StartsWith "" @> genereert een expressieboom die er zo uitziet: Call (Some (Value ("")), StartsWith, [Value ("")]) . Deze expressieboom komt overeen met wat getMethodInfo verwacht en geeft de juiste methode-informatie terug.

Hiermee worden alle hierboven genoemde problemen opgelost.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow