首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何通过在F#中为每个延迟对象创建值来转换包含延迟对象的异构数组(没有反射)

如何通过在F#中为每个延迟对象创建值来转换包含延迟对象的异构数组(没有反射)
EN

Stack Overflow用户
提问于 2021-06-02 03:28:38
回答 3查看 81关注 0票数 1

我如何实现转型

代码语言:javascript
运行
复制
let args : Object[] = [| lazy 7; "text"; lazy "lazytext" |]

转到

代码语言:javascript
运行
复制
[| 7; "text"; "lazytext" |]

这不起作用:

代码语言:javascript
运行
复制
let createvalue<'t> (v: Object) : Object =
    match v with
    | :? Lazy<'t> as x -> x.Value :> Object
    | x -> x

args |> Array.map createvalue

因为createvalue<'t>被编译器认为是createvalue<obj>的,所以第一个模式大小写不匹配。

一种低效的解决方案是反射:

代码语言:javascript
运行
复制
let createvalue (v: Object) : Object =
    match v with
    | _ when v.GetType().Name = "Lazy`1" ->
        v.GetType().InvokeMember("Value", BindingFlags.GetProperty, null, v, [||])
    | x -> x

但是有没有一种干净、直接的F#方法呢?

EN

回答 3

Stack Overflow用户

发布于 2021-06-02 06:05:45

我不认为使用异构的Lazy<'T>元素可以很好地做到这一点,但是既然您无论如何都要丢弃类型信息,您会考虑让它们都变成Lazy<obj>吗?如果是这样的话,解决方案是干净的:

代码语言:javascript
运行
复制
let args : obj[] = [| lazy box 7; "text"; lazy box "lazytext" |]

let createvalue (v: obj) : obj =
    match v with
    | :? Lazy<obj> as x -> x.Value
    | x -> x
票数 1
EN

Stack Overflow用户

发布于 2021-06-02 06:58:09

您不能这样做。

让我们来看看你使用的东西的类型:

代码语言:javascript
运行
复制
let args : Object[] = [| lazy 7; "text"; lazy "lazytext" |]

let createValue<'t> (v: obj) : obj = ...

module Array =
    let inline map (mapping: 't -> 'u) (array:'t[]) = ...

因此,通过所有的泛型,乍一看,您试图做的事情似乎是正确的。但是如果仔细观察,就会发现在映射函数createValue<'t>(obj)中,实际上是obj,它在Array.map中用作't类型。所以如果我们填入类型,你会得到这样的结果(并且使用这个createValue返回一个对象):

代码语言:javascript
运行
复制
let args : Object[] = [| lazy 7; "text"; lazy "lazytext" |]

let createValue<'t> (v: obj) : obj =
    match v with
    | :? Lazy<'t> as x -> x.Value :> Object
    | x -> x

module Array =
    let inline map (mapping: obj -> obj) (array:obj[]) = ...

这表明,在本例中,Array.map只接受了来自obj -> obj的函数。但是你的createValue<'otherT>(obj):obj仍然是泛型的,所以F#会推断出obj的类型,因为你不需要对类型做任何事情,所以F#会推断出‘'otherT’。因此,您传入的函数将类似于:

代码语言:javascript
运行
复制
let createValue (v: obj) : obj =
    match v with
    | :? Lazy<obj> as x -> x.Value :> Object
    | x -> x

您还可以传递createValue的其他具体版本。例如,如果你使用args |> Array.map createvalue<int>,那么它将在所有的int实例上正常工作,但对于其他任何实例都不能。

如果你知道lazy可以包含的类型,你可以这样做:

代码语言:javascript
运行
复制
let createvalue (v: obj) : obj =
    match v with
    | :? Lazy<int> as x -> x.Value :> obj
    | :? Lazy<string> as x -> x.Value :> obj
    | x -> x

但如果你不这样做,我担心你会陷入反思,或者像brianberns建议的那样改变你的方法。

票数 1
EN

Stack Overflow用户

发布于 2021-06-02 03:38:06

只需将createvalue设置为内联函数,它就会工作。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67794942

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档