Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Reflection F#-如何根据返回类型动态创建异步函数_Reflection_F#_Metaprogramming - Fatal编程技术网

Reflection F#-如何根据返回类型动态创建异步函数

Reflection F#-如何根据返回类型动态创建异步函数,reflection,f#,metaprogramming,Reflection,F#,Metaprogramming,我试图动态创建一个函数,它可以根据F#中的输入返回不同的类型。这些类型的函数类似于代理,为了说明我正在尝试做什么,下面是一个无法正常工作的示例: open FSharp.Reflection open System let functionThatReturnsAsync (irrelevantArgs: obj list) (returnType: Type) = if returnType.GUID = typeof<string>.GUID then asy

我试图动态创建一个函数,它可以根据F#中的输入返回不同的类型。这些类型的函数类似于代理,为了说明我正在尝试做什么,下面是一个无法正常工作的示例:

open FSharp.Reflection
open System

let functionThatReturnsAsync (irrelevantArgs: obj list) (returnType: Type) = 
    if returnType.GUID = typeof<string>.GUID
    then async { return box "some text" } 
    elif returnType.GUID = typeof<int>.GUID
    then async { return box 42 }
    elif returnType.GUID = typeof<bool>.GUID
    then async { return box true }
    else async { return box null }

// this works fine
let func = FSharpValue.MakeFunction(typeof<string -> Async<int>>, fun x -> box (functionThatReturnsAsync [x] typeof<int>))

// unboxing to that type works as well
let fn = unbox<string -> Async<int>> func 

async {
    // HERE THE ERROR
    let! output = fn "hello"
    printfn "%d" output
}
|> Async.StartImmediate

这是否可能,并使该示例起作用?我甚至不介意摆弄IL-emits来让它工作,但我不知道如何工作。如果问题不清楚,请告诉我,我会更新

我会利用泛型来实现这一点,而不是尝试动态创建函数。这是您的代码,已修改为利用泛型类型:

open FSharp.Reflection
open System

let functionThatReturnsAsync<'a> (irrelevantArgs: obj list) = 
    match Unchecked.defaultof<'a> |> box with
    | :? Guid -> async { return box "some text" } 
    | :? Int32 -> async { return box 42 }
    | :? Boolean -> async { return box true }
    | _ -> async { return box null }


// unboxing to that type works as well
let fn<'a> input = 
    async {    
        let! result = functionThatReturnsAsync<'a> [input |> box]
        return result |> unbox<'a>
    }

// This works now
async {
    let! output = fn<int> "hello"
    printfn "%d" output
}
|> Async.RunSynchronously
打开FSharp.Reflection
开放系统
让返回同步|>框的函数与
| :? Guid->异步{返回框“某些文本”}
| :? Int32->异步{返回框42}
| :? 布尔->异步{返回框true}
|->async{return box null}
//取消绑定到该类型也可以
设fn[输入|>框]

返回结果|>unbox如果您可以像亚伦建议的那样利用泛型,那么这样做将是一个更好的主意。但是,如果您需要在运行时选择一种类型,则可以通过将返回sync的
函数更改为如下所示,使代码正常工作:

let functionThatReturnsAsync (irrelevantArgs: obj list) (returnType: Type) = 
    if returnType.GUID = typeof<string>.GUID
    then box (async { return "some text" })
    elif returnType.GUID = typeof<int>.GUID
    then box (async { return 42 })
    elif returnType.GUID = typeof<bool>.GUID
    then box (async { return true })
    else box (async { return (null:obj) })
let函数returnsasync(不相关的args:obj列表)(returnType:Type)=
如果returnType.GUID=typeof.GUID
然后框(异步{return“some text”})
elif returnType.GUID=typeof.GUID
然后框(异步{return 42})
elif returnType.GUID=typeof.GUID
然后框(异步{return true})
else框(异步{返回(null:obj)})

这与您所做的几乎相同-但它不是在异步计算中装箱值,而是装箱整个异步计算(然后返回正确类型的值)-因此强制转换工作正常

问题是,异步中的返回值总是被装箱为obj,我从JSON中获取值并动态反序列化为正确的
returnType
,因此我认为正因为如此,即使装箱整个异步也不能解决问题。如果只有一个非通用的
unbox(t:Type,o:obj)
我可以使用,但我在任何地方都找不到。@ZaidAjaj很难想象具体的场景是什么-你能用代码发布一个新问题,演示这个答案没有解决的方面吗?我试图动态创建一个记录,作为代理对象,每个字段都是函数,根据输入和输出类型提供每个功能的实现。该实现是一个POST请求,它将JSON结果反序列化为相应函数的正确返回类型。使用反射似乎太难了,需要在运行时进行太多的修改才能使其正常工作,我求助于引用并获得了一个优雅的解决方案,我将在发布代码时发布结果(之前/之后的代码),因为这是历史上的一些提交,非常感谢您的帮助!我认为我的例子过于简化了我的原始问题,您在运行时看到的所有函数类型都只能在运行时使用,所以
result |>unbox
let functionThatReturnsAsync (irrelevantArgs: obj list) (returnType: Type) = 
    if returnType.GUID = typeof<string>.GUID
    then box (async { return "some text" })
    elif returnType.GUID = typeof<int>.GUID
    then box (async { return 42 })
    elif returnType.GUID = typeof<bool>.GUID
    then box (async { return true })
    else box (async { return (null:obj) })