Получить тип .NET из Mono.Cecil

Я работаю над приложением .NET. В моем приложении я должен проверить, реализуют ли типы в сборке определенный интерфейс. В моей сборке есть пакет из пакета NuGet (зависимость), поэтому я использую Mono.Cecil для получения всех типов в сборке. Код:

ModuleDefinition module = ModuleDefinition.ReadModule(assemblyPath);
Collection<TypeDefinition> t1 = module.Types;

Проблема в том, что Mono.Cecil возвращает TypeDefinition, а не Type. Так можно ли в любом случае преобразовать каждый TypeDefinition в коллекции в тип .NET, чтобы я мог легко проверить, реализует ли этот тип конкретный интерфейс или нет?

Любая помощь приветствуется.


person Waleed Naveed    schedule 05.07.2020    source источник
comment
Есть ли причина, по которой вы должны использовать Cecil и не можете напрямую использовать классы Assembly/Type? (т.е. загрузка сборки с помощью Load/LoadFile, а затем использование GetTypes и т. д.)   -  person pinkfloydx33    schedule 06.07.2020
comment
да, в моей сборке установлен пакет NuGet, и в этом случае я не могу использовать простой класс Assembly/Type. @pinkfloydx33   -  person Waleed Naveed    schedule 06.07.2020
comment
Я не понимаю, почему бы и нет. Зависимости Nuget копируются в выходной каталог. Если вы уже ссылаетесь на типы в этой сборке, это так же просто, как typeof(SomethingInNuget).Assembly, но в противном случае путь будет рядом с вашей сборкой, поэтому я запутался   -  person pinkfloydx33    schedule 06.07.2020
comment
сборка = Assembly.Load(File.ReadAllBytes(assemblyPath)); foreach (Введите t в сборке.GetExportedTypes()){} . . . . На foreach я получаю исключение Не удалось загрузить файл или сборку «Кварц». .@pinkfloydx33   -  person Waleed Naveed    schedule 06.07.2020
comment
Попробуйте использовать LoadFrom с путем к сборке или Load с AssemblyName (если вы не знаете, что означает AssemblyName, найдите его, потому что это не совсем то, что вы ожидаете сразу). Загрузка из массива байтов, по-видимому, не загружает зависимости сборки (что имеет смысл без специального события Assembly Resolve, чтобы знать, где искать)   -  person pinkfloydx33    schedule 06.07.2020


Ответы (1)


Если вы можете использовать полное имя интерфейса, то вам не нужно Type, достаточно TypeDefinition. Пример (на F#):

let myInterface = "Elastic.Apm.Api.ITracer"

let implementsInterface (t : Mono.Cecil.TypeDefinition) =
  t.HasInterfaces
  && t.Interfaces |> Seq.exists (fun i -> i.InterfaceType.FullName = myInterface)

let getTypes assemblyFileName =
  Mono.Cecil.AssemblyDefinition
    .ReadAssembly(fileName = assemblyFileName).MainModule.Types
  |> Seq.filter implementsInterface
  |> Seq.map (fun t -> t.FullName)
  |> Seq.toArray

let ts = getTypes assemblyFile
printfn "Types implementing %s: %A" myInterface ts
// Output:
// Types implementing Elastic.Apm.Api.ITracer: [|"Elastic.Apm.Api.Tracer"|]
person Gebb    schedule 05.07.2020
comment
Я могу использовать полное имя интерфейса, но мне нужен тип внутри сборки, которая реализует интерфейс, поскольку мне нужно выполнить некоторую обработку, для которой требуется тип. - person Waleed Naveed; 06.07.2020
comment
Можете ли вы загрузить эту сборку через отражение? Если это так, вы можете получить свой тип по полному имени. assembly.GetType("Your.Type.Full.Name") - person Gebb; 06.07.2020