Hi,
reflection is probably the best alternative (meaning that it will internaly use .NET reflection), but you can simplify the code by using F# reflection library and also use it together with F# quotations to get a surprising degree of compile-time checking.
#light
open System
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.Typed
open Microsoft.FSharp.Quotations.Raw
type SampleRec = {
Str : string
Num : int }
// This function takes a quotation with a "hole" (which is represented as a function)
// The type 'a is a type of the record and the type 'b is a type of the field, so we can
// use this type information and return a function 'a -> 'b which takes a record value
// and reads the field (you can of course remove the "unbox" function and it would
// return just 'obj' type, which may be sometimes more useful)
let getValueReader (prop:Expr<'a> -> Expr<'b>) =
let rcTy = typeof<'a>
// fill in the hole with some dummy quotation - we just want to get
// the representation of quotation as "Expr" and not as a function
let expr = prop (Typed.of_raw (MkHole rcTy))
// Analyze the qutotation...
match expr.Raw with
| RecdGet (ty, nm, expr) ->
// It represents an access to a record value, so we can use F# Reflection
// to get a function "rdr" that reads a specified field of the record
let rdr = Reflection.Value.GetRecordFieldReader (ty, nm)
((box >> rdr >> unbox) : 'a -> 'b)
| _ ->
// Not an access to a record field - fail
failwith "Invalid expression - not reading record field!"
// Create a 'reader' from a quotation
// Note that these two are typed (SampleRec -> string / int)
let rdS = getValueReader <@ (_ : SampleRec).Str @>
let rdN = getValueReader <@ (_ : SampleRec).Num @>
let rc = { Str = "Hello world!"; Num = 42 }
let v1 = rdS rc
let v2 = rdN rc
printfn "Extracted: %s, %d" v1 v2
Console.ReadLine() |> ignore
BTW: This is a really interesting question, so thanks for it! I'm really interested in hearing more about your problem and whether this solution will be helpful for you.
T.
Tomas Petricek (
Blog), C# MVP
My book:
Real-world Functional Programming in .NET