获取泛型类子类型列表

3

我有一个通用类,有许多子类型:

public abstract class MyClass<T> : MyBaseClass where T : class
{...}

public class MySubClassA : MyClass<A>
{...}

public class MySubClassB : MyClass<B>
{...}

有没有一种简单的方法来搜索 MyClass 的子类并获得一个包含 MySubClassA 和 MySubClassB 的 IEnumerable<Type>?

我以前用过这种方法,但不确定如何将其适应于泛型:

public static IEnumerable<Type> GetSubTypesOf(Type t, bool baseAssemblyOnly = false)
{
    List<Type> types = new List<Type>();
    Assembly[] searchAssemblies = baseAssemblyOnly
        ? new[] { Assembly.GetAssembly(t) }
        : AppDomain.CurrentDomain.GetAssemblies();
    foreach (Assembly a in searchAssemblies)
    {
        types.AddRange(a.GetTypes()
                        .Where(myType => myType.IsClass
                                      && !myType.IsAbstract
                                      && myType.IsSubclassOf(t)));
    }
    return types;
}

我不清楚你发布的代码为什么实际上不能工作。看起来你会调用GetSubTypesOf(typeof(MyClass<T>)),对吧? - Moby Disk
我可以调用 GetSubTypesOf(typeof(MyClass<A>)) 来获取 MySubClassA,但我不想在特定 T 的上下文中调用它。我想要调用 "所有 Ts",例如 GetSubTypesOf(typeof(MyClass<*>))。 - Chris B
2个回答

3

这有点复杂,因为你需要搜索类型的基本类型,以找到与 MyClass<> 的开放泛型类型定义匹配的类型。您可以定义几个帮助方法:

public static IEnumerable<Type> BaseTypesOf(Type t)
{
    while (t != null)
    {
        yield return t;
        t = t.BaseType;
    }
}

public static Type FindGenericBaseTypeOf(Type t, Type openType)
{
    return BaseTypesOf(t)
        .FirstOrDefault(bt => bt.IsGenericType && bt.GetGenericTypeDefinition() == openType);
}

然后,您可以将它们应用于要搜索的类型的输入序列,例如。
var types = Assembly.GetExecutingAssembly().GetTypes()
    .Where(t => t.IsClass && !t.IsAbstract)
    .Select(t => new { Type = t, GenericBase = FindGenericBaseTypeOf(t, typeof(MyClass<>)) })
    .Where(ts => ts.GenericBase != null)
    .Select(ts => ts.GenericBase.GetGenericArguments().First())
    .ToArray();

关键是GetGenericTypeDefinition(): https://msdn.microsoft.com/zh-cn/library/system.type.getgenerictypedefinition.aspx - Moby Disk

2
问题在于当你将typeof(MyClass<>)传递给t参数时,你并没有传递一个实例化的泛型类型,而是传递了一个泛型类型定义。这意味着你的任何类都不会响应IsSubclassOf(t)
你可以按照以下方式修复代码:
List<Type> types = searchAssemblies
    .SelectMany(a => 
        a.GetTypes()
        .Where(myType => myType.IsClass && !myType.IsAbstract && HasGenericBase(myType, t))
    ).ToList();
...
private static bool HasGenericBase(Type myType, Type t) {
    Debug.Assert(t.IsGenericTypeDefinition);
    while (myType != typeof(object)) {
        if (myType.IsGenericType && myType.GetGenericTypeDefinition() == t) {
            return true;
        }
        myType = myType.BaseType;
    }
    return false;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接