2016-03-27 10 views
3

特定の属性とタイプのletバインディングを特定のアセンブリ全体で検索しようとしています。モジュール内の属性とタイプ別にバインディングを反映する

たとえば、次の型および属性:

type TargetType = { somedata: string } 
type MarkingAttribute() = inherit System.Attribute() 

その後、私は、次のモジュールで値を見つけるしたいと思います:

module SomeModule = 
    [<Marking>] 
    let valueIWantToFind = {somedata = "yoyo"} 

だから私は何を探していますが持つ機能であります次のシグネチャ(一般的な関数シグネチャに適していると仮定します):

let valuesOfTypeWithAttribute<'t,'attr> (assembly: Assembly) : 't list = ... 

私の無駄な試みは、F#モジュールがどのようにCLR(CLI?)クラスに変換されているのか理解できないためにブロックされているようです。

open System.Reflection 
let types = Assembly.GetExecutingAssembly().GetTypes() 

let fiWithAttribute (attributeType: System.Type) (fi: FieldInfo) = 
    fi.CustomAttributes 
    |> Seq.exists (fun attr -> attr.AttributeType = attributeType) 

let fields = 
    types 
    |> Array.collect (fun t -> t.GetFields()) 
    |> Array.filter (fiWithAttribute typeof<MarkingAttribute>) 

すべてのヘルプやポインタを非常に高く評価されます。

は、私は残念ながら何も見つかっていない、次のFSIスニペットを持っています。

+1

使う代わりに、GetMembersれるGetFields - http://ideone.com/UIRgay ​​ –

+2

ILSpyを使用し、スタッフが翻訳されてどのように把握します。 –

答えて

2

マークの反応は私を成功の道に導いた。リフレクションはFSIで完全に定義されたモジュールでは機能しません(少なくとも私の設定ではそうではありません)。

私はこのようなルックスを思い付いた機能:

open Microsoft.FSharp.Reflection 
let letBindingsWithTypeAndAttribute<'t,'attr> (assembly: Assembly) : 't array = 
    let publicTypes = assembly.GetExportedTypes() 
    let modules = publicTypes |> Array.filter FSharpType.IsModule 
    let members = modules |> Array.collect (fun m -> m.GetMembers()) 

    let miHasAttribute (mi : MemberInfo) = 
     mi.GetCustomAttributes() 
     |> Seq.exists (fun attr' -> attr'.GetType() = typeof<'attr>) 

    let withAttr = 
     members 
     |> Array.filter miHasAttribute 

    let valueOfBinding (mi : MemberInfo) = 
     let property = mi.Name 
     mi.DeclaringType.GetProperty(property).GetValue null 

    withAttr 
     |> Array.map valueOfBinding 
     |> Array.choose (fun o -> match o with 
            | :? 't as x -> Some x 
            | _ -> None) 
3

モジュールは、静的メンバーを持つクラスとしてコンパイルされます。 assemblyと呼ばれる値にあなたのアセンブリをロードし、調査を開始:あなたが言うことができるように

> let publicTypes = assembly.GetExportedTypes();; 

val publicTypes : System.Type [] = 
    [|Ploeh.StackOverflow.Q36245870.TargetType; 
    Ploeh.StackOverflow.Q36245870.MarkingAttribute; 
    Ploeh.StackOverflow.Q36245870.SomeModule|] 

を、SomeModuleは、これらのタイプのいずれかです。

> let someModule = 
    publicTypes |> Array.find (fun t -> t.Name.EndsWith "SomeModule");; 

val someModule : System.Type = Ploeh.StackOverflow.Q36245870.SomeModule 

あなたは今のタイプのすべてのメンバーを取得することができます:

> let members = someModule.GetMembers();; 

val members : MemberInfo [] = 
    [|Ploeh.StackOverflow.Q36245870.TargetType get_valueIWantToFind(); 
    System.String ToString(); Boolean Equals(System.Object); 
    Int32 GetHashCode(); System.Type GetType(); 
    Ploeh.StackOverflow.Q36245870.TargetType valueIWantToFind|] 

この配列には、LET結合機能valueIWantToFindを含み、それが必要な属性を持っています

> let attrs = members.[5].GetCustomAttributes();; 

val attrs : System.Collections.Generic.IEnumerable<System.Attribute> = 
    [|Ploeh.StackOverflow.Q36245870.MarkingAttribute; 
    Microsoft.FSharp.Core.CompilationMappingAttribute|] 
関連する問題