gpt4 book ai didi

list - 如何在 F# 中将对象强制转换为泛型类型列表

转载 作者:行者123 更新时间:2023-12-04 12:14:58 24 4
gpt4 key购买 nike

在下面的代码片段中,我的目的是将 System.Object(可能是 FSharpList)转换为它所持有的任何泛型类型的列表。

    match o with
| :? list<_> -> addChildList(o :?> list<_>)
| _ -> addChild(o)

可惜只有 list<obj>永远匹配为列表。我要 list<Foo>也可以作为列表匹配。

对于某些上下文,我试图通过反射遍历对象结构,以便构建类及其子项的 TreeView。考虑以下类:
type Entity = {
Transform : Matrix
Components : obj list
Children : Entity list
}

我想构建一棵树,显示实体中包含的所有类。
通过反射,我可以获得一个对象的所有属性以及它们的值(值很重要,因为我想用元素的 Name 属性在列表中显示不同的元素,如果它有的话):
        let o = propertyInfo.GetValue(obj, null)

该值可能是某种类型的列表,但返回值只是一个 System.Object
尝试将此对象转换为列表时遇到问题。我被迫执行以下操作:
        match o with
| :? list<obj> -> addChildList(o :?> list<obj>)
| :? list<Entity> -> addChildList(o :?> list<Entity>)
| _ -> addChild(o)

在这里,我必须准确指定我要转换为的类型。
我真的很想写这个:
        match o with
| :? list<_> -> addChildList(o :?> list<_>)
| _ -> addChild(o)

不幸的是,这只匹配于 list< obj >

最佳答案

不幸的是,没有简单的方法可以做你想做的事。类型测试只能用于特定类型,即使类型测试通过,转换操作符:?>也只能将表达式转换为特定类型,因此匹配的右侧无论如何都不会执行您想要的操作。您可以使用事件模式部分解决此问题:

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

let ( |GenericType|_| ) =
(* methodinfo for typedefof<_> *)
let tdo =
let (Call(None,t,[])) = <@ typedefof<_> @>
t.GetGenericMethodDefinition()
(* match type t against generic def g *)
let rec tymatch t (g:Type) =
if t = typeof<obj> then None
elif g.IsInterface then
let ints = if t.IsInterface then [|t|] else t.GetInterfaces()
ints |> Seq.tryPick (fun t -> if (t.GetGenericTypeDefinition() = g) then Some(t.GetGenericArguments()) else None)
elif t.IsGenericType && t.GetGenericTypeDefinition() = g then
Some(t.GetGenericArguments())
else
tymatch (t.BaseType) g
fun (e:Expr<Type>) (t:Type) ->
match e with
| Call(None,mi,[]) ->
if (mi.GetGenericMethodDefinition() = tdo) then
let [|ty|] = mi.GetGenericArguments()
if ty.IsGenericType then
let tydef = ty.GetGenericTypeDefinition()
tymatch t tydef
else None
else
None
| _ -> None

此事件模式可按如下方式使用:
match o.GetType() with
| GenericType <@ typedefof<list<_>> @> [|t|] -> addChildListUntyped(t,o)
| _ -> addChild(o)

您在其中创建了 addChildList 的变体类型为 t和一个对象 o (运行时类型 list<t> )而不是采用通用列表。

这有点笨拙,但我想不出更干净的解决方案。

关于list - 如何在 F# 中将对象强制转换为泛型类型列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2140079/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com