Как бросить объект к списку универсального типа в F#

В следующем отрывке мое намерение состоит в том, чтобы преобразовать Систему. Объект (который мог быть 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)

Это значение могло быть списком некоторого типа, но возвратом значения является просто Система. Возразите, что я сталкиваюсь с проблемами при попытке преобразовать этот объект в список. Я вынужден сделать следующее:

        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 >

7
задан Johan 26 January 2010 в 14:44
поделиться

2 ответа

Оказывается, что либо list<'a>, либо array<'a> могут быть сопоставлены как seq

    match o with
    | :? seq<obj> -> addChildCollection(o :?> seq<obj>)
    | _           -> addChild(o)

Меня не очень волнует, что это список. До тех пор, пока я могу выполнять итерации над ним.

1
ответ дан 7 December 2019 в 10:01
поделиться

К сожалению, нет простого способа сделать то, что вы хотите. Тип тесты можно использовать только с конкретными типами, и даже если прошел тест типа, оператор преобразования :?> также работает только для литых выражений для определенных типов, поэтому правая сторона вашего матча не будет Делайте то, что вы хотите все равно. Вы можете частично работать по этому вопросу, используя активную картину:

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 (с типом выполнения в списке ) вместо того, чтобы принимать универсальный список.

Это немного неуместно, но я не могу думать о чистом решении.

5
ответ дан 7 December 2019 в 10:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: