我试图在给定的程序集中找到具有特定属性和类型的绑定。
例如,以下类型和属性:
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片段,遗憾的是一无所获:
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>)
非常感谢任何帮助或指示。
答案 0 :(得分: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-bound函数valueIWantToFind
,它具有所需的属性:
> let attrs = members.[5].GetCustomAttributes ();;
val attrs : System.Collections.Generic.IEnumerable<System.Attribute> =
[|Ploeh.StackOverflow.Q36245870.MarkingAttribute;
Microsoft.FSharp.Core.CompilationMappingAttribute|]
答案 1 :(得分:2)
我想出的功能如下:
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)