'Get all sub classes of generic abstract base class

I have a generic base class and I eventually would have many derived classes. I am trying to write a function which would return all these sub classes but everything I have tried so far has not worked.

public abstract class Index<T>
    where T : class
{
    public abstract string IndexName { get; }

    public abstract string TypeName { get; }

    public abstract Expression<Func<T, IConvertible>> IdFieldSelector { get; }

    public string MakeSearchId(T item)
    {
        return ToSearchId(IdFieldSelector.Compile().Invoke(item));
    }

    public string MakeSearchId(IConvertible idValue)
    {
        return ToSearchId(idValue);
    }

    private static string ToSearchId(IConvertible idValue)
    {
        return idValue.ToString(CultureInfo.InvariantCulture);
    }
}

sample subclass:

public class SurveyChangedIndex : Index<SurveyChanged>
{
    public override string IndexName => "reviews";

    public override string TypeName => "review";

    public override Expression<Func<SurveyChanged, IConvertible>> IdFieldSelector => sc => sc.SurveyResponseId;
}

sample function:

        var indexBase = typeof(Index<>);
        var indexes = Assembly.GetAssembly(indexBase)
            .GetTypes()
            .Where(type =>
                type != indexBase &&
                !type.IsInterface &&
                !type.IsAbstract &&
                type.BaseType == indexBase)
            .ToList();


Solution 1:[1]

You can do the following (C# 7 syntax follows):

public static IEnumerable<Type> GetAllDescendantsOf(
    this Assembly assembly, 
    Type genericTypeDefinition)
{
    IEnumerable<Type> GetAllAscendants(Type t)
    {
        var current = t;

        while (current.BaseType != typeof(object))
        {
            yield return current.BaseType;
            current = current.BaseType;
        }
    }

    if (assembly == null)
        throw new ArgumentNullException(nameof(assembly));

    if (genericTypeDefinition == null)
        throw new ArgumentNullException(nameof(genericTypeDefinition));

    if (!genericTypeDefinition.IsGenericTypeDefinition)
        throw new ArgumentException(
            "Specified type is not a valid generic type definition.", 
            nameof(genericTypeDefinition));

    return assembly.GetTypes()
                   .Where(t => GetAllAscendants(t).Any(d =>
                       d.IsGenericType &&
                       d.GetGenericTypeDefinition()
                        .Equals(genericTypeDefinition)));
}

This will return any type that inherits directly or indirectly from the specified generic type definition.

In the following scenario:

class Base { }
class Base<T>: Base { }
class Foo : Base<int> { }
class Bar : Base<string> { }
class Frob : Bar { }
class FooBar: Base { };

var genericTypeDefinition = typeof(Base<>);
var types = Assembly.GetExecutingAssembly()
                    .GetAllDescendantsOf(genericTypeDefinition)));

GetAllDescendantsOf will output Foo, Bar and Frob.

Solution 2:[2]

This should solve your code:

var indexes = Assembly.GetAssembly(indexBase)
     .GetTypes()
     .Where(type =>
         type != indexBase &&
         !type.IsInterface &&
         !type.IsAbstract &&
         type.BaseType.IsAssignableFrom(indexBase))
     .ToList();

Solution 3:[3]

This worked for me:

var indexes = Assembly.GetAssembly(indexBase)
    .GetTypes()
    .Where(IsIndexType)
    .ToArray();

with

private bool IsIndexType(Type type)
{
    var indexDefinition = typeof(Index<>).GetGenericTypeDefinition();
    return !type.IsAbstract
           && type.IsClass
           && type.BaseType is not null
           && type.BaseType.IsGenericType
           && type.BaseType.GetGenericTypeDefinition() == indexDefinition;
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 CodeTherapist
Solution 3 user1007074