Reflection F#-如何根据返回类型动态创建异步函数
我试图动态创建一个函数,它可以根据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
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) })