Найти все указанные c типы с отражением в сборках, загруженных приложением с ядром. net - PullRequest
1 голос
/ 24 февраля 2020

Примечание: хотя пример кода написан на F #, я специально не ищу ответ F #, но для вызовов. net, которые мне нужно сделать, поэтому ответ на C# или F # подойдет.

У меня есть система, в которой есть команды для чат-бота, разбросанные по разным частям кода. Я нахожу и регистрирую их все через отражение, используя этот код:

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

Это в F #, но я думаю, что вызовы методов выдают то, что он делает, если вы более знакомы с C#.

Итак, я делаю Assembly.GetTypes, сохраняйте те, где GetInterface имеет имя интерфейса, которое я ищу, и затем я создаю их экземпляр.

Это работает хорошо, но только в пределах своей сборки. У меня вопрос, как я могу расширить это на все сборки, загруженные приложением (но системные, чтобы не тратить время)?

Ответы [ 2 ]

1 голос
/ 24 февраля 2020

Пусть ваши пользовательские сборки определяют атрибут уровня сборки, который вы можете проверить, чтобы принять решение о дальнейшем сканировании библиотеки. Это более надежно, чем определение того, какие сборки включены в черный список, например, вы можете не сканировать 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")

Если ваши требования будут более сложными в будущем, возможно, стоит взглянуть на MEF.

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

let instances = container.GetExports<IBotCommands, IBotCommandMetadata>()
1 голос
/ 24 февраля 2020

Вы можете использовать Assembly.GetReferencedAssemblies на t.Assembly, отфильтровывать System ссылок по их имени и затем Assembly.Load по именам для загрузки последовательности сборок. Оттуда вы можете сделать Seq.collect на Assembly.GetTypes().

...