F # , , , F # PowerPack. , , F #:
open Microsoft.FSharp.Reflection
let applyOnFields (recd1:'T) (recd2:'T) f =
let flds1 = FSharpValue.GetRecordFields(recd1)
let flds2 = FSharpValue.GetRecordFields(recd2)
let flds = Array.zip flds1 flds2 |> Array.map f
FSharpValue.MakeRecord(typeof<'T>, flds)
, f . , ( ):
type R = { X : string ; Y : string }
let a = { X = null ; Y = "##" }
let b = { X = "##" ; Y = null }
let selectNotNull (x:obj, y) =
if String.IsNullOrWhiteSpace (unbox x) then y else x
let c = applyOnFields a b selectNotNull
Reflection , . .NET Reflection , applyOnFields. AST, , , . - :
let applyOnFields (a:R) (b:R) f = { X = f (a.X, b.X); Y = f (a.Y, b.Y) }
, , :
open Microsoft.FSharp.Quotations
let flds = FSharpType.GetRecordFields(typeof<R>) |> List.ofSeq
let aVar = Var.Global("a", typeof<R>)
let bVar = Var.Global("b", typeof<R>)
let args = flds |> List.map (fun fld ->
let arg = Expr.NewTuple [ Expr.PropertyGet(Expr.Var(aVar), fld)
Expr.PropertyGet(Expr.Var(bVar), fld) ]
Expr.App(???, args)
let body = Expr.NewRecord(typeof<R>, args)
, F # PowerPack. . .