【问题标题】:Reflecting let bindings in a module by attribute and type通过属性和类型反映模块中的 let 绑定
【发布时间】:2016-03-27 21:18:51
【问题描述】:

我正在尝试在给定程序集中查找具有特定属性和类型的 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?)类而受阻。

我有以下 FSI sn-p,但遗憾的是什么也没找到:

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>)

任何帮助或指点将不胜感激。

【问题讨论】:

  • 使用 GetMembers 代替 GetFields - ideone.com/UIRgay
  • 要弄清楚内容是如何翻译的,请使用 ILSpy。

标签: f# system.reflection


【解决方案1】:

模块被编译为具有静态成员的类。将您的程序集加载到名为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-bound 函数valueIWantToFind,并且它具有所需的属性:

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

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

【讨论】:

    【解决方案2】:

    Mark 的回答让我走上了成功之路。反射不适用于完全在 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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多