【问题标题】:Dynamically cast 'obj' to function type indicated by reflection将“对象”动态转换为反射指示的函数类型
【发布时间】:2015-05-12 18:12:54
【问题描述】:

我正在对 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类型,它们的类型只有在运行时才知道,所以怎么能我这样做?

请注意,genericTypeInstantiation 是一个 System.Type,它包含 validator 参数的类型。

【问题讨论】:

    标签: f#


    【解决方案1】:

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

    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 "..."
    

    【讨论】:

      猜你喜欢
      • 2016-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-06
      相关资源
      最近更新 更多