Пожалуйста, прочитайте весь вопрос. У меня уникальная ситуация с несколькими ограничениями, которые я хотел бы решить.
В моем коде есть дерево выражений, которое скомпилировано в Predicate
. Моя цель - загрузить сборку, не блокируя ее (это выходная сборка проекта, которая постоянно перестраивается ), применить этот предикат к списку ее типов и получить обратно список результирующего типа имена:
// this is what I need:
return assembly.GetTypes().Where(t => predicate(t)).Select(t => t.FullName);
Эта сборка должна быть загружена в другом домене приложения, потому что я хочу выгрузить ее, как только получу требуемую информацию.
Здесь все становится сложнее. Есть несколько проблем, с которыми я сталкиваюсь.:
Если я загружаю сборку в другой домен приложения и просто возвращаю массив всех ее типов,чтобы я мог применить предикат обратно в свой основной домен приложения, как только типы будут упорядочены обратно в мой основной домен приложения, я получаю FileNotFoundException
, утверждающий, что эта сборка не найдена. Это имеет смысл, потому что сборка загружается только в другом созданном мной домене приложения. Загрузка его также в основной домен приложения приведет к поражению цели.
Если, в качестве альтернативы, я попытаюсь передать предикат в другой домен приложения, чтобы применить его там и получить обратно массив строк (полное имя типа ), я получаю SerializationException: "Cannot serialize delegates over unmanaged function pointers, dynamic methods or methods outside the delegate creator's assembly."
, потому что предикат Динамический метод (, скомпилированный из дерева выражений ).
Загрузка в основной домен приложения не вызовет никаких проблем, но, поскольку невозможно выгрузить загруженную сборку без выгрузки всего домена приложения, как только сборка изменится (после перестроения ), любая попытка загрузка сборки с тем же именем приведет к исключению.
Контекст:
Я создаю подключаемый модуль для ReSharper под названием Agent Mulder . Идея плагина заключается в анализе регистраций контейнеров DI/IoC в вашем решении и помощи ReSharper в определении использования типов, зарегистрированных через контейнер DI (. Вы можете посмотреть короткое видео о том, как это работает здесь ). ].
По большей части анализ регистрации контейнеров не вызывает затруднений. -Мне достаточно собрать достаточно информации, чтобы узнать, какие конкретные типы затронуты. В этом примере с замком Виндзор:Component.For
результирующий тип очевиден, поэтомуAllTypes.FromThisAssembly().BasedOn
-дает мне достаточно информации, чтобы приблизительно оценить конкретные типы, на которые повлияет эта строка. Однако рассмотрим эту регистрацию в источнике Castle Windsor:
container.Register(Classes
.FromAssemblyInDirectory(new AssemblyFilter(".").FilterByName(an => an.Name.StartsWith("Ploeh.Samples.Booking")))
.Where(t => !(t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Dispatcher<>)))
.WithServiceAllInterfaces());
. Здесь информация зависит от предиката, который будет оцениваться только во время выполнения.
Поскольку все, что я могу сделать, это статически проанализировать это, у меня в руках AST ReSharper (, называемый PSI в ReSharper )представлении лямбда-выражения из предложения Where
.Я могу преобразовать этот AST в дерево выражений LINQ, а затем скомпилировать его в делегат.
Моя идея заключалась в том, чтобы загрузить выходную сборку (, определенную FromAssembly*
дескриптором )посредством отражения, и применить этот делегат к типам сборки, чтобы получить имена типов (Мне нужны только имена ). Это также нужно -оценивать каждый раз, когда изменяется сборка (На данный момент я не беспокоюсь о производительности ).
В заключение, если кто-то не может порекомендовать лучший способ определения типов, затронутых предикатом, я хотел бы знать, как это сделать с помощью отражения (К сожалению, я не рассматривал другие программы чтения метаданных, потому что я d нужно каким-то образом преобразовать лямбда-выражение AST в предикат другого типа данных, и я не знаю, существует ли преобразование 1 -в -1 ).
Спасибо, что прочитали. Когда этот вопрос станет доступным, награда за этот вопрос составит 500 баллов.