Страницы

Поиск по вопросам

среда, 29 января 2020 г.

Поиск сборки (алгоритм)

#c_sharp #net #clr


Подскажите оптимальный способ поиска сборки. Например в папке лежит 1k сборок (*.dll)
и нужно выбрать например две специальные сборки. Как нужно пометить (атрибуты? вроде
медленно будет искать рефлекшеном)  специфические сборки, для быстрого поиска в другой
программе? 

Может есть какой то способ дописать что то в мета-таблцицы сборки что бы очень быстро
можно было прочитать и понят эта та сборка, что нужно, или нет?
    


Ответы

Ответ 1



Вы можете воспользоваться библиотекой Mono.Cecil (доступна так же через NuGet) и использовать ее для анализа сборок. Для теста я взял почти все сборки из GAC, скопировал их, чтобы получилось ~1 тысяча сборок, добавил туда несколько экземпляров моих библиотек с искомым атрибутом и выполнил такой код: var assemblys = Directory.GetFiles("C:\\dlls\\") .Select(AssemblyDefinition.ReadAssembly) .Where(assembly => assembly.CustomAttributes.Any(ca=> ca.AttributeType.Name == "MyCustomAttribute")) .ToList(); Результат он выдал через ~600 миллисекунд (мерил с помощью Stopwatch). Мне кажется, что этого может быть для Вас достаточно.

Ответ 2



Основная потеря скорости будет при загрузке сборки в домен. Дальнейший анализ сборки, по сравнению с ее загрузкой, дешев, так что там хоть атрибут вешайте, хоть что. Если пойдете по этому пути, не забудьте делать это в отдельном аппдомене, чтобы потом выгрузить ненужные сборки. Что можно придумать без загрузки всех сборок в домен: Самым быстрым вариантом будет поиск сборки просто по имени. Подписать сборки определенным ключом. При поиске считывать ключ и сравнивать с нужным. Обозначить сборки фиктивной версией (например, 127.0.0.1). При поиске считывать версию. Попробовать дописать несколько байт в dll, закодировав в них свой маркер, не повредив при этом сборки. Дальше открывать сборки как байт стримы и считывать маркеры.

Ответ 3



Я сталкивался с подобной проблемой, и решил её для себя при помощи статического определения нужных библиотек. То есть при компиляции/установке программы специальная утилита определяет, какие из сборок нужно загрузить, и складывает эти данные в специальное место (например, файл). Теперь основная программа должна просто прочитать этот файл и загрузить нужные сборки, без необходимости рантайм-тестирования. При добавлении сборок в каталог (или удалении из него) должна автоматически запускаться та же утилита, которая будет обновлять список. Разрешать пользователю добавлять/убирать сборки руками не нужно. С другой стороны, если вы пишете плагинную систему, возможно, вам нужно не изобретать велосипед, и воспользоваться встроенным фреймворком System.AddIn.

Ответ 4



Я не знаю, подойдет ли данное решение для вашей задачи. Но смысл примерно в следующем: Вам понадобится интерфейс, который описывает функциональность классов, которые будут загружаться из сборок: public interface ISomeTypeInterface { string Name { get; } } После этого в сборках вы объявляете типы следующим образом: [Export(typeof(ISomeTypeInterface))] public class SomeType1 : ISomeTypeInterface { public string Name { get { return "Hello, world!"; } } } Далее, в месте, где нужно это все собрать пишете: class SomeClass { [ImportMany] private ISomeTypeInterface[] SomeTypes { get; set; } } void ComposeParts() { var someClass = new SomeClass(); // Каталог, в котором нужно искать типы можно настраивать более тонко, используя других наследников ComposablePartCatalog или создавая своих using (var catalog = new DirectoryCatalog(".")) using (var container = new CompositionContainer(catalog)) { container.ComposeParts(someClass); } foreach (var t in someClass.SomeTypes) { Console.WriteLine(t.Name); } } Если вам подойдет такой алгоритм работы с типами, то я бы советовал использовать MEF. Не могу сказать о скорости работы. У нас не возникало необходимости ускорить этот механизм, хоть он и используется часто и густо.

Комментариев нет:

Отправить комментарий