Sök…


Robust reflektion med F # -noteringar

Reflektion är användbar men ömtålig. Tänk på detta:

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

Problemen med den här typen av kod är:

  1. Koden fungerar inte eftersom det finns flera överbelastningar av String.StartsWith
  2. Även om det inte skulle finnas några överbelastningar just nu kan senare versioner av biblioteket lägga till en överbelastning som orsakar en körtid
  3. Refactoring verktyg som Rename methods bryts med reflektion.

Det betyder att vi får en körtidskrasch för något som är känt kompileringstid. Det verkar suboptimalt.

Med F# offert är det möjligt att undvika alla ovanstående problem. Vi definierar några hjälpfunktioner:

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

Vi använder funktionerna så här:

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

Detta skriver ut:

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

<@ ... @> betyder att istället för att köra uttrycket inuti F# genereras ett uttrycksträd som representerar uttrycket. <@ "".StartsWith "" @> genererar ett uttrycksträd som ser ut så här: Call (Some (Value ("")), StartsWith, [Value ("")]) . Detta uttrycksträd matchar vad getMethodInfo förväntar sig och det kommer att returnera korrekt metodinfo.

Detta löser alla ovanstående problem.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow