Создание списка дочерних классов с отражением в .NET 3.5

Во время выполнения я хотел бы указать родительский класс, а затем программа сгенерировала бы список всех дочерних классов (скольких бы поколений). Например, если бы у меня был Entity в качестве родителя, а также Item:Entity и Actor:Entity, было бы две строки: «Актер» и «Элемент».

Я вижу, что System.Reflection.TypeInfo это именно то, что я ищу. Однако похоже, что это эксклюзивно для .NET 4.5, и моя среда, к сожалению, застряла на 3.5.

Есть ли альтернативный способ сделать это в .NET 3.5 или мне следует подумать об обновлении?


person Kyle Baran    schedule 15.12.2012    source источник


Ответы (3)


var pType = typeof(Entity);
IEnumerable<string> children = Enumerable.Range(1, iterations)
   .SelectMany(i => Assembly.GetExecutingAssembly().GetTypes()
                    .Where(t => t.IsClass && t != pType
                            && pType.IsAssignableFrom(t))
                    .Select(t => t.Name));

Демо

person Tim Schmelter    schedule 15.12.2012

Один из возможных способов — использовать метод Type.IsAssignableFrom. Вы бы перебрали все типы и выбрали те, для которых это верно.

В принципе, это будет что-то вроде

Type parent = Type.GetType("Entity");
Type[] types = Assembly.GetExecutingAssembly().GetTypes(); // Maybe select some other assembly here, depending on what you need
Type[] inheritingTypes = types.Where(t => parent.IsAssignableFrom(t));

В настоящее время у меня нет доступного компилятора, поэтому я не могу его проверить, но в основном он должен быть правильным.

person carlpett    schedule 15.12.2012
comment
О, отлично, я собирался спросить, как лучше всего создать список, и это более или менее метод, который был рекомендован при быстром поиске SO. - person Kyle Baran; 16.12.2012
comment
Я укажу, что Assembly.GetExecutingAssembly() не будет работать за пределами сборки. Если вы хотите работать со сборками, вы можете использовать AppDomain.CurrentDomain.GetAssemblies(). - person Kendall Frey; 16.12.2012
comment
@Danjen: обратите внимание, что это также вернет интерфейсы и сам родительский класс. Если это не нужно, вам нужно немного отфильтровать. Кроме того, как отмечает Кендалл, вам нужно немного подумать о том, какую сборку/сборки вы хотите искать. Но это должно заставить вас начать. - person carlpett; 16.12.2012

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

public class InheritedFinder
{
    public static Type[] FindInheritedTypes(
        Type parentType, Assembly assembly)
    {
        Type[] allTypes = assembly.GetTypes();
        ArrayList avTypesAL = new ArrayList();

        return allTypes.Where(
            t => parentType.IsAssignableFrom(t) && t != parentType).ToArray();
    }
}

Просто позвоните по

var availableTypes = InheritedFinder.FindInheritedTypes(
        typeof(YourBaseClass),
        System.Reflection.Assembly.GetExecutingAssembly());

Это даст вам список доступных дочерних элементов YourBaseClass. Хорошая вещь об этом - он также найдет детей детей, так что вы можете использовать многоуровневые абстрактные классы. Если вам нужно создать экземпляры каждого дочернего элемента, легко:

var availableTypes= InheritedFinder.FindInheritedTypes(
    typeof(Shape), System.Reflection.Assembly.GetExecutingAssembly());
foreach (var t in availableTypes)
{
    try
    {
        YourBaseClass nInstance = (YourBaseClass)Activator.CreateInstance(t);
        //nInstance is now real instance of some children
    }
    catch (Exception e)
    {
        //recommended to keep here - it'll catch exception in case some class is abstract (=can't create its instance)
    }
}
person Michal Pokluda    schedule 30.03.2020