2017-02-16 11 views
4

,listまたはseqのときに、さまざまなプロパティを持つtypeのプロパティが抽出されます。シーケンス(配列、リスト、seq)の基礎となる型を取得

type Car = { name: string } 
type CarStore = 
    { name: string 
    cars: Car[] 
    names: string list 
    others: string seq 
    others2: ResizeArray<string> } 

let peek x = 
    Dump x 
    x 

let extractTypeInfo name (typ:Type) = 
    let isEnumerable = true //todo: true for list, array, seq, etc 
    let underlyingType = typ //todo: if isEnumerable = true, get actual type 
    isEnumerable, underlyingType 

typeof<CarStore>.GetProperties() 
|> peek 
|> Seq.map (fun p -> extractTypeInfo p.Name p.PropertyType) 
|> Dump 

上記の次のプロパティを与える実行以下

サンプルコード、

  • 名:String
  • 車:IStructuralEquatable[]
  • 名:FSharpList<String>
  • その他:IEnumerable<String>
  • その他2:String
  • 車:Car
  • 名:String
  • 結果が

    • 名以下の情報を持つことになりますようにextractTypeInfo更新する必要がありますどのようにList<String>

    その他:String

  • その他2:String

答えて

8

私はこのような何かを傾けているはずだ:

let extractTypeInfo (typ:Type) = 
    typ.GetInterfaces() 
    |> Array.tryFind (fun iFace -> 
     iFace.IsGenericType && iFace.GetGenericTypeDefinition() = typedefof<seq<_>>) 
    |> Option.map (fun iFace -> iFace.GetGenericArguments().[0]) 

このアプローチは、タイプがSomeまたはNone'Tの種類を返すことによってseq<'T>であるかどうかを取り込み、 Someケースの結果内にあります。

FSIでのいくつかの例:TheInnerLightの答え@

extractTypeInfo typeof<float array>;; 
val it : System.Type option = 
    Some 
    System.Double ... 

extractTypeInfo typeof<string list>;; 
val it : System.Type option = 
    Some 
    System.String ... 

extractTypeInfo typeof<int>;; 
val it : System.Type option = None 
+0

上記の関数は配列とリストのため正常に動作します。しかし、 'String'はCharに縮小されますが、これは異なる扱いが可能な辺の場合です。 'string seq'は' None'になります。私は上記の関数を使って他のケースを特定しています。 – Richard

5

は、良好な作業ソリューションを与えるが、反射といつものように、あなたが本当にあなたを見て何をしたいかについて非常に意識する必要があります本当に見ている。

  1. F#の型システムは、配列が適切な汎用型のように見える一方では、これは彼らが.NETのリフレクションAPIに表示する方法はありません:

    は、私はここで注目すべき2つの微妙な点があると感じ。配列型を指定すると、はfalseになりますが、typ.IsArraytrueと等しくなり、typ.GetElementType()で型パラメータを取得できます。これは、リフレクションAPIが.NETジェネリックに先立つため、歴史的な理由によるものです。

  2. IEnumerable<'a>のインターフェイス実装のジェネリック型の引数は、その型でのみです。これは、リスト、配列、配列のみを考慮した場合、型とインタフェースのジェネリック型引数は同じですが、一般的には与えられていないことを意味します。あなたはそのIEnumerable<'a>実装とは異なるタイプの引数(これは地図や辞書の場合である)、またはIEnumerable<'a>の複数の実装(その場合には、このソリューションは、最初に見つかったものをピックアップします)とを使用してインスタンス化ジェネリック型を持つことができます。

これらは、ソリューションにとって重要と思われるものではない場合がありますが、間に合う可能性があります。

+0

情報ありがとうございます。残念なことに私の場合、これらは重要なことです。さらなる処理のために正確なタイプが必要です。 – Richard

関連する問題