代码之家  ›  专栏  ›  技术社区  ›  Junior

如何在C#中使用反射查找实现泛型抽象类的所有类?

  •  3
  • Junior  · 技术社区  · 6 年前

    我有一个 c#

    public abstract class Listener<T> where T : Event
    {
        public abstract void Handle(T _event);
    }
    

    我把这门课扩展成这样

    public class SendWelcomeEmail : Listener<UserWasCreated>
    {
        public override void Handle(UserWasCreated _event)
        {
            //...
        }
    }
    

    我需要使用反射来查找扩展 Listener<> 基类。

    我试了以下方法

    var listeners = AppDomain.CurrentDomain.GetAssemblies()
                             .SelectMany(assembly => assembly.GetTypes())
                             .Where(x => x.IsClass && !x.IsInterface)
                             .Where(listener => !listener.IsAbstract && listener.IsGenericType && listener.GetGenericTypeDefinition() == typeof(Listener<>))
                             .ToList();
    

    但这并没有带来任何回报。此条件始终返回false listener.GetGenericTypeDefinition() == typeof(Listener<>)

    侦听器<&燃气轮机;

    2 回复  |  直到 6 年前
        1
  •  17
  •   Eric Lippert    6 年前

    从构建所需的基础设施开始:在工具箱中放入更多工具,然后使用这些工具。

    static class Extensions
    {
    public static IEnumerable<Type> BaseTypes(this Type type)
    {
        Type t = type;
        while (true)
        {
            t = t.BaseType;
            if (t == null) break;
            yield return t;
        }
    }
    }
    

    现在我们的工具箱里有了一个有用的工具。

    我们手头有一台打字机。我们想知道它的任何基类型是否正确。因此我们应该使用 Any :

    static bool AnyBaseType(this Type type, Func<Type, bool> predicate) =>
      type.BaseTypes().Any(predicate);
    

    现在我们有了另一个有用的工具。

    我们想知道特定类型是否为特定泛型:

    static bool IsParticularGeneric(this Type type, Type generic) =>
      type.IsGenericType && type.GetGenericTypeDefinition() == generic;
    

    我们想知道特定类型是否是侦听器:

    static bool IsListener(Type type) =>
      type.IsParticularGeneric(typeof(Listener<>));
    

    现在我们有了我们需要的工具。

    var listeners = from assembly in AppDomain.CurrentDomain.GetAssemblies()
                    from type in assembly.GetTypes()
                    where type.AnyBaseType(IsListener)
                    select type;
    

    看看当你一次建立一个你需要的工具时,查询是多么容易阅读?我们想知道什么? 如果任何基类型是侦听器

        2
  •  5
  •   Cyril Gandon niktrs    6 年前

    你可以发现任何基类型都是a Listener<> ,通过递归检查是目标类型 IsInheritedFrom 信息技术:

    public static class Extension
    {
        public static bool IsInheritedFrom(this Type type, Type Lookup)
        {
            var baseType = type.BaseType;
            if (baseType == null)
                return false;
    
            if (baseType.IsGenericType
                    && baseType.GetGenericTypeDefinition() == Lookup)
                return true;
    
            return baseType.IsInheritedFrom(Lookup);
        }
    }
    
    var lookup = typeof(Listener<>);
    var listeners = AppDomain.CurrentDomain.GetAssemblies()
        .SelectMany(assembly => assembly.GetTypes())
        .Where(x => x.IsClass && !x.IsAbstract && x.IsInheritedFrom(lookup))
        .ToList();