获取泛型类

时间:2015-09-15 20:28:53

标签: c# generics inheritance polymorphism

我有一个包含许多子类型的泛型类:

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

2 个答案:

答案 0 :(得分: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();

答案 1 :(得分: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;
}