List 如何将对象强制转换为F中泛型类型的列表#

List 如何将对象强制转换为F中泛型类型的列表#,list,f#,generics,casting,List,F#,Generics,Casting,在下面的代码片段中,我的意图是将System.Object(可以是FSharpList)转换为它所持有的任何泛型类型的列表 match o with | :? list<_> -> addChildList(o :?> list<_>) | _ -> addChild(o) 我想构建一个树,显示实体中包含的所有类。 通过反射,我可以获得对象的所有属性以及它们的

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

    match o with
    | :? list<_>              -> addChildList(o :?> list<_>)
    | _                       -> addChild(o)
我想构建一个树,显示实体中包含的所有类。 通过反射,我可以获得对象的所有属性以及它们的值(该值很重要,因为我想在列表中显示不同的元素,如果元素有Name属性,则该列表中包含该元素的Name属性):

该值可以是某种类型的列表,但返回的值只是一个System.Object 我在尝试将此对象转换为列表时遇到问题。我被迫做以下事情:

        match o with
        | :? list<obj>              -> addChildList(o :?> list<obj>)
        | :? list<Entity>           -> addChildList(o :?> list<Entity>)
        | _                         -> addChild(o)
将o与
| :? 列表->添加子列表(o:?>列表)
| :? 列表->添加子列表(o:?>列表)
|_u->addChild(o)
在这里,我必须准确地指定要转换的类型。
我真的很想写这封信:

        match o with
        | :? list<_>              -> addChildList(o :?> list<_>)
        | _                       -> addChild(o)
将o与
| :? 列表->添加子列表(o:?>列表)
|_u->addChild(o)

不幸的是,这只在
列表

上匹配。不幸的是,没有简单的方法来做你想做的事情。类型测试只能与特定类型一起使用,即使类型测试通过,转换运算符
:?>
也只能将表达式强制转换为特定类型,这样匹配的右侧就不会执行您想要的操作。您可以使用活动模式部分解决此问题:

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
打开Microsoft.FSharp.quotes
打开Microsoft.FSharp.quotes.Patterns
let(| GenericType | | |)=
(*methodinfo用于typedefof*)
设tdo=
让(调用(None,t,[])=
t、 GetGenericMethodDefinition()
(*将类型t与通用def g*匹配)
let rec tymatch t(g:类型)=
如果t=typeof,则无
伊里夫·g·伊斯界面
设ints=if t.IsInterface然后[| t |]else t.GetInterfaces()
ints |>Seq.tryPick(fun t->if(t.GetGenericTypeDefinition()=g)然后是一些(t.GetGenericArguments())或者没有)
elif t.IsGenericType&&t.GetGenericTypeDefinition()=g然后
一些(t.GetGenericArguments())
其他的
tymatch(t.BaseType)g
乐趣(e:Expr)(t:Type)->
匹配
|呼叫(无,mi,[])->
如果(mi.GetGenericMethodDefinition()=tdo),则
let[| ty |]=mi.GetGenericArguments()
如果ty.IsGenericType,则
设tydef=ty.GetGenericTypeDefinition()
tymatch t tydef
没有别的
其他的
没有一个
|无
此活动模式可按如下方式使用:

match o.GetType() with
| GenericType <@ typedefof<list<_>> @> [|t|] -> addChildListUntyped(t,o)
| _                                          -> addChild(o)
将o.GetType()与
|GenericType[| t |]->addChildListUntyped(t,o)
|_u->addChild(o)
您已经创建了一个
addChildList
变体,它采用类型
t
和对象
o
(使用运行时类型
list
),而不是采用通用列表


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

结果是
list
可以匹配为
seq

将o与
| :? seq->addChildCollection(o:?>seq)
|_u->addChild(o)

我真的不在乎它是一个列表。只要我能重复一遍。

你真的需要键入的列表吗?在我看来,匹配
IEnumerable
就足够了。这在.NET 4.0上应该可以工作,但在以前的版本上不起作用,因为
同样,我认为像
这样进行模式匹配会稍微干净一些:?seq as s->addChildCollection(s)
,这样您就不会有明显的沮丧情绪。当我需要均匀地对待列表时,这个小把戏只是帮了我一把。谢谢
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)
    match o with
    | :? seq<obj> -> addChildCollection(o :?> seq<obj>)
    | _           -> addChild(o)