动态演员' obj'到反射指示的功能类型

时间:2015-05-12 18:12:54

标签: f#

我模式匹配F#引用,并希望调用引号内引用的函数。简化代码如下所示:

open Microsoft.FSharp.Quotations.Patterns
open Microsoft.FSharp.Quotations.DerivedPatterns

let ModelValidator (validator : 'T -> bool) (valueToValidate : 'T) : 'T = 
    failwith "Don't call me!"

let foo expr =
    match expr with
    | SpecificCall <@ ModelValidator @> (None, genericTypeInstantiation::[], 
                                        [ Value(validator, validatorType); source ]) ->
        let value = getValue source // Will return an 'obj'
        // Now, I want to call 'validator value', but how?
        // This will obviously not work, but it shows in principle what I want to do:
        let castedValue : genericTypeInstantiation = unbox value
        let castedFunction : genericTypeInstantiation -> bool = unbox validator
        castedFunction castedValue
    | _ -> failwith "..."


let myIntValidator (x : int) =
    x = 42

let myStringValidator (x : string) =
    x = "foo"

let a = foo <@ ModelValidator myIntValidator 44 @>
let b = foo <@ ModelValidator myStringValidator "bar" @>

虚函数ModelValidator是通用的,用作一种占位符或标记,即在模式匹配中放入匹配大小写的东西。它还有助于在报价中强制实施类型安全。

在调用ModelValidator的匹配案例中,我想致电validator value,但validatorvalue都属于obj类型类型只在运行时知道,所以我该怎么做?

请注意,genericTypeInstantiationSystem.Type,其中包含validator参数的类型。

1 个答案:

答案 0 :(得分:3)

你应该可以用一点反射魔法来做到这一点

open Microsoft.FSharp.Quotations.Patterns
open Microsoft.FSharp.Quotations.DerivedPatterns

let ModelValidator (validator : 'T -> bool) (valueToValidate : 'T) : 'T = 
    failwith "Don't call me!"

type Invoker private () =
    static let CallMethodInfo = 
        let flags = System.Reflection.BindingFlags.NonPublic ||| System.Reflection.BindingFlags.Static
        typeof<Invoker>.GetMethod("DoCall", flags).GetGenericMethodDefinition()

    static member private DoCall<'T>(validator: obj, value: obj): bool =
        let validator: 'T -> bool = unbox validator
        let value: 'T = unbox value
        validator value

    static member Call(validator: obj, value: obj, typeOfValue: System.Type): bool =
        CallMethodInfo.MakeGenericMethod(typeOfValue).Invoke(null, [|validator; value|]) :?> _

let foo expr =
    match expr with
    | SpecificCall <@ ModelValidator @> (None, [genericTypeInstantiation], [ Value(validator, validatorType); source ]) ->
        let value = getValue source // Will return an 'obj'
        Invoker.Call(validator, value, genericTypeInstantiation)
    | _ -> failwith "..."