简体   繁体   English

在由具有 .net 内核的应用程序加载的程序集中,通过反射查找所有特定类型

[英]Find all specific types, with reflection, in assemblies loaded by the application with .net core

Note: although the example code is in F#, I'm not specifically looking for a F# answer but for the .net calls I need to do, so an answer in C# or F# is fine.注意:虽然示例代码在 F# 中,但我并不是专门寻找 F# 的答案,而是我需要做的 .net 调用,所以 C# 或 F# 中的答案是可以的。

I have a system where there are commands, for a chat bot, scattered in different part of the code.我有一个系统,其中有命令,用于聊天机器人,分散在代码的不同部分。 I find, and register, them all through reflection using this code:我使用这段代码通过反射找到并注册了它们:

member private this.RegisterCommands() =
    let t = typeof<IBotCommands>
    t.Assembly.GetTypes()
    |> Seq.filter (fun x -> x.GetInterface(t.Name) <> null)
    |> Seq.iter (fun x ->
        (
            let i = (Activator.CreateInstance(x)) :?> IBotCommands
            botCommands.[i.Name()] <- i
            i.Initialize(this)
        )
    )

It's in F#, but I think the method calls give away what it does if you're more familiar with C#.它在 F# 中,但我认为如果您更熟悉 C#,方法调用就会泄露它的作用。

So, I do Assembly.GetTypes, keep the ones where GetInterface has the interface name I'm looking for and then I instantiate them.因此,我执行 Assembly.GetTypes,保留 GetInterface 具有我正在寻找的接口名称的那些,然后实例化它们。

This works well, but only within its own assembly.这很好用,但只在它自己的程序集中。 My question is how can I expand this to all assemblies loaded by the app (but the system ones to not waste time)?我的问题是如何将其扩展到应用程序加载的所有程序集(但系统程序集不会浪费时间)?

You can use Assembly.GetReferencedAssemblies on t.Assembly , filter out System references by their name and then Assembly.Load on the names to load a sequence of assemblies.您可以在t.Assembly上使用Assembly.GetReferencedAssemblies ,按名称过滤掉System引用,然后在名称上使用Assembly.Load以加载一系列程序集。 From there you can do a Seq.collect on Assembly.GetTypes() .从那里您可以在Assembly.GetTypes()上执行Seq.collect

Have your user assemblies define an assembly level attribute - which you can check for, to decide further scan the library.让您的用户程序集定义程序集级别的属性 - 您可以检查该属性,以决定进一步扫描库。 This is more robust than figuring out which assemblies to black-list, for eg, you may not want to scan Newtonsoft.Json .这比确定将哪些程序集列入黑名单更可靠,例如,您可能不想扫描Newtonsoft.Json

   Assembly
       .GetEntryAssembly()   
       .GetReferencedAssemblies()    
       |> Seq.map    (fun assm -> Assembly.Load assm.FullName)
       |> Seq.append (Seq.singleton (Assembly.GetEntryAssembly()))
       |> Seq.filter (fun assm -> assm.IsDefined(useAttrib) )
       |> Seq.collect(fun assm -> assm.GetTypes())       
       |> Seq.filter (fun x -> interfaceType.IsAssignableFrom(x))
       |> Seq.iter (printfn "%A")

If your requirements are going to be more complex in the future, it might be worth taking a look at MEF.如果您的要求将来会变得更加复杂,那么 MEF 可能值得一看。

let catalog = new DirectoryCatalog("./")
let container = new CompositionContainer(catalog)
container.ComposeParts()

let instances = container.GetExports<IBotCommands, IBotCommandMetadata>()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM