Извлечение объектов, реализующих интерфейс, из нескольких сборок

Я хотел бы получить перечисление созданных классов, которые реализуют интерфейс из нескольких сборок в папке решения.

У меня есть следующая структура папок (если это имеет смысл):

Solution
   -SolutionFolder
      - Project1
          - class implementing interface I would like to find
          - other classes

      - Project2
          - class implementing interface I would like to find
          - other classes

   -MainProject
      - classes where my code is running in which I would like to retrieve the list of classes

Следовательно, если реализуемый интерфейс — ISettings, то я хотел бы, чтобы IEnumerable<ISettings> ссылался на созданные объекты этого интерфейса.

До сих пор я использовал отражение для извлечения классов, реализующих интерфейс, из известного имени класса:

IEnumerable<ISettings> configuration = 
                (from t in Assembly.GetAssembly(typeof(CLASSNAME-THAT-IMPLEMENTs-INTERFACE-HERE)).GetTypes()
                 where t.GetInterfaces().Contains(typeof(ISettings)) && t.GetConstructor(Type.EmptyTypes) != null
                 select (ISettings)Activator.CreateInstance(t)).ToList();

но это одна сборка, и я не буду знать имена классов.

Можно ли этого добиться с помощью отражения или для этого требуется нечто большее?


person Dangerous    schedule 01.02.2012    source источник


Ответы (2)


Пока вы говорите только о сборках, которые загружаются в AppDomain (что они должны быть, чтобы делать то, что вам нужно), вы можете использовать что-то вроде этого для их итерации:

AppDomain.CurrentDomain
         .GetAssemblies().ToList()
         .ForEach(a => /* Insert code to work with assembly here */);

Или, если вы загрузили их в другой домен приложения, вы можете использовать экземпляр вместо AppDomain.CurrentDomain выше.

person M.Babcock    schedule 01.02.2012
comment
Спасибо за ваш ответ. Однако мои сборки не будут изначально загружены в домен приложения, и мне может потребоваться подключить дополнительные сборки, избегая перекомпиляции основного проекта (что-то, что я не ясно дал понять в своем первоначальном вопросе, я извиняюсь). - person Dangerous; 03.02.2012
comment
Вы можете использовать комбинацию кода из вашего вопроса, кода из моего ответа и Assembly.Load во время выполнения для динамической загрузки сборок в ваш домен приложения. Ваши плагины будут выполняться только в том случае, если вы их все равно загрузите. - person M.Babcock; 03.02.2012

Чтобы решить эту проблему, я установил событие после сборки каждого проекта в папке решения, чтобы скопировать его сборку в папку bin в папке bin основных проектов.

Событие после сборки было установлено аналогично:

copy "$(TargetPath)" "$(SolutionDir)MainProjectName\bin"

Затем я использовал следующее, чтобы получить имена файлов сборки из этого каталога bin (благодаря Дарину за его сообщение о решении здесь):

string[] assemblyFiles = Directory.GetFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin"), "*.dll");

Затем я получил реализации объектов, реализующих интерфейс ISettings, используя:

IEnumerable<ISettings> configuration = assemblyFiles.Select(f => Assembly.LoadFrom(f))
                .SelectMany(a => a.GetTypes())
                .Where(t => t.GetInterfaces().Contains(typeof(ISettings)) && t.GetConstructor(Type.EmptyTypes) != null)
                .Select(t => (ISettings)Activator.CreateInstance(t));

Это позволяет мне добавлять дополнительные проекты, реализующие настройки, без перекомпиляции основного проекта.

Кроме того, одной альтернативой, которую я рассмотрел, было использование MEF, где введение можно найти здесь .

person Dangerous    schedule 03.02.2012