инкапсуляция c#: получение типов из другого проекта


Мне нужно немного объяснить, чтобы добраться до проблемы.

У меня есть 3 проекта:

Проект 1 может видеть проекты 2 и 3.

Проект 2 может видеть проект 3.

Project 3-это dll, а остальные-приложения.

Мне пришлось разработать класс с большим количеством подклассов. У всех подклассов есть метод, который объявлен как абстрактный в базе, поэтому они все должны использовать его. Они должны быть распределены во всех проектах, потому что код в methode напрямую взаимодействует с проект.

Абстрактные базовые классы находятся в проекте 3, подклассы-в 2 и 1. Вот проблема, которая у меня есть:

Это метод, который я написал:

   public static IEnumerable<Type> GetSubClasses(Type typ)
   {
       IEnumerable<Type> subclasses =
       from type in Assembly.GetAssembly(typ).GetTypes()
       where type.IsSubclassOf(typ) && !type.IsAbstract
       select type;
       return subclasses;
   }
Я пытаюсь получить все подклассы этого типа, но когда я это делаю, я получаю только подклассы из текущего проекта. Например, если я попытаюсь получить их из проекта 1, я не получу подклассы из проекта 2.

Как мне это сделать? Я знаю, что могу получить ссылку на сборку из проекта 2, но у него нет GetAssembly(тип Т) метод, с помощью которого я получаю все подклассы. Если бы это было то же самое, я просто должен был сделать то же самое там.

Мой второй вопрос: есть ли вообще более простой способ? Это немного.."большой" имея эти классы во многих проектах, возможно, есть решение, чтобы получить их в один. Как я уже сказал, код methode, который они все должны иметь, должен непосредственно взаимодействовать с проектом, в котором они находятся.

3 2

3 ответа:

Проблема в том, что вы звоните Assembly.GetTypes(). Это дает вам только классы в этой конкретной сборке. Если у вас есть объекты Assembly для всех трех сборок, вы можете сделать что-то вроде

assem1.GetTypes()
.Concat(assem2.GetTypes())
.Concat(assem3.GetTypes())
Таким образом, проблема заключается в том, как вы получаете три объекта Assembly. Из проекта 1 Вы можете просто сказать
var assem1 = typeof(SomeClassInProj1).Assembly;
var assem2 = typeof(SomeClassInProj2).Assembly;
var assem3 = typeof(SomeClassInProj3).Assembly;

В проекте, где вы не можете "видеть" другие сборки, вам нужно загрузить их. Смотрите документацию по Assembly.Load.

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

Аналогичным образом, сборка, экспортирующая открытые типы, не предназначена для того, чтобы знать что-либо об импортерах. Если сделать это с "ранним привязыванием", то получится круговая ссылка.

Можно было бы точно отразить все сборки, загруженные в домен приложения, и посмотреть, какие из них наследуются от определенного типа но что вы намерены делать с этой информацией? Вероятно, есть более простой и быстрый способ достичь этого.

Вы должны загрузить все сборки, которые могут содержать типы, которые вы хотите найти, и искать типы, как вы делаете в цикле.

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

// load all files from current dir which ends with `.dll`
var q = from s in Directory.GetFiles(Directory.GetCurrentDirectory(), "*.dll")
        select s;

var types = q.Select(s => getTypes(s, myBaseType))
             .SelectMany(typeList => typeList).ToList();

И функция getTypes:

IEnumerable<Type> getTypes(string filePath, Type baseType) {
    Assembly a = Assembly.LoadFrom(filePath);
    return a.GetTypes().Where(t => t.IsSubclassOf(baseType) && !t.IsAbstract);
}

Вы должны иметь дело с некоторыми исключениями, такими как BadImageFormatException, когда у вас есть dll в папке, которые не являются сборками .net.

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