获取通用抽象基 class 的所有子 classes

Get all sub classes of generic abstract base class

我有一个通用的基础 class,我最终会有很多派生的 classes。 我正在尝试编写一个函数,它将 return 所有这些子 classes 但到目前为止我尝试的一切都没有奏效。

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);
    }
}

子样本class:

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;
}

示例函数:

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

这应该可以解决您的代码问题:

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

您可以执行以下操作(C# 7 语法如下):

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)));
}

这将 return 直接或间接继承自指定泛型类型定义的任何类型。

在以下情况下:

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 将输出 FooBarFrob.

这对我有用:

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

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;
}