【问题标题】:Get all types implementing specific open generic type获取所有实现特定开放泛型类型的类型
【发布时间】:2020-04-01 04:19:21
【问题描述】:

如何获得所有实现特定开放泛型类型的类型?

例如:

public interface IUserRepository : IRepository<User>

找出所有实现IRepository&lt;&gt;的类型。

public static IEnumerable<Type> GetAllTypesImplementingOpenGenericType(Type openGenericType, Assembly assembly)
{
  ...
}

【问题讨论】:

    标签: c# generics reflection open-generics


    【解决方案1】:

    这将返回所有继承通用基类的类型。并非所有类型都继承泛型接口。

    var AllTypesOfIRepository = from x in Assembly.GetAssembly(typeof(AnyTypeInTargetAssembly)).GetTypes()
     let y = x.BaseType
     where !x.IsAbstract && !x.IsInterface &&
     y != null && y.IsGenericType &&
     y.GetGenericTypeDefinition() == typeof(IRepository<>)
     select x;
    

    这将返回所有类型,包括在其继承链中具有开放泛型类型的接口、抽象和具体类型。

    public static IEnumerable<Type> GetAllTypesImplementingOpenGenericType(Type openGenericType, Assembly assembly)
    {
        return from x in assembly.GetTypes()
                from z in x.GetInterfaces()
                let y = x.BaseType
                where
                (y != null && y.IsGenericType &&
                openGenericType.IsAssignableFrom(y.GetGenericTypeDefinition())) ||
                (z.IsGenericType &&
                openGenericType.IsAssignableFrom(z.GetGenericTypeDefinition()))
                select x;
    }
    

    第二种方法将在此示例中找到 ConcreteUserRepoIUserRepository

    public class ConcreteUserRepo : IUserRepository
    {}
    
    public interface IUserRepository : IRepository<User>
    {}
    
    public interface IRepository<User>
    {}
    
    public class User
    {}
    

    【讨论】:

    • 是的,但是只有在同一个程序集中时,您才能获得具体的repo 和 irepo。但这绝对没问题。
    • 好收获!我们必须小心加载所有依赖程序集,而不仅仅是扫描当前加载的程序集。这是关于加载所有程序集的 SO:stackoverflow.com/questions/2384592/…
    • typeof(IRepository) 仅在泛型类型具有单个泛型参数时才有效。对于具有多个泛型类型参数的类型有什么想法吗?
    • 对不起,我找到了答案。您所要做的就是 typeof(IRepository) (假设有两个泛型类型参数)等等!酷!
    • 这不是只有在具体类型直接继承被搜索的接口时才有效吗?
    【解决方案2】:

    在没有 LINQ 的情况下实现的解决方案,搜索泛型和非泛型接口,将返回类型过滤到类。

    public static class SampleCode
    {
        public static void Main()
        {
            IList<Type> loadableTypes;
    
            // instance the dummy class used to find the current assembly
            DummyClass dc = new DummyClass();
    
            loadableTypes = GetClassesImplementingAnInterface(dc.GetType().Assembly, typeof(IMsgXX)).Item2;
            foreach (var item in loadableTypes) {Console.WriteLine("1: " + item);}
            // print
            // 1: Start2.MessageHandlerXY
    
            loadableTypes = GetClassesImplementingAnInterface(dc.GetType().Assembly, typeof(IHandleMessageG<>)).Item2;
            foreach (var item in loadableTypes) { Console.WriteLine("2: " + item); }
            // print
            // 2: Start2.MessageHandlerXY
            // 2: Start2.MessageHandlerZZ
        }
    
        ///<summary>Read all classes in an assembly that implement an interface (generic, or not generic)</summary>
        //
        // some references
        // return all types implementing an interface
        // http://stackoverflow.com/questions/26733/getting-all-types-that-implement-an-interface/12602220#12602220
        // http://haacked.com/archive/2012/07/23/get-all-types-in-an-assembly.aspx/
        // http://stackoverflow.com/questions/7889228/how-to-prevent-reflectiontypeloadexception-when-calling-assembly-gettypes
        // return all types implementing a generic interface
        // http://stackoverflow.com/questions/33694960/find-all-types-implementing-a-certain-generic-interface-with-specific-t-type
        // http://stackoverflow.com/questions/8645430/get-all-types-implementing-specific-open-generic-type
        // http://stackoverflow.com/questions/1121834/finding-out-if-a-type-implements-a-generic-interface
        // http://stackoverflow.com/questions/5849210/net-getting-all-implementations-of-a-generic-interface
        public static Tuple<bool, IList<Type>> GetClassesImplementingAnInterface(Assembly assemblyToScan, Type implementedInterface)
        {
            if (assemblyToScan == null)
                return Tuple.Create(false, (IList<Type>)null);
    
            if (implementedInterface == null || !implementedInterface.IsInterface)
                return Tuple.Create(false, (IList<Type>)null);
    
            IEnumerable<Type> typesInTheAssembly;
    
            try
            {
                typesInTheAssembly = assemblyToScan.GetTypes();
            }
            catch (ReflectionTypeLoadException e)
            {
                typesInTheAssembly = e.Types.Where(t => t != null);
            }
    
            IList<Type> classesImplementingInterface = new List<Type>();
    
            // if the interface is a generic interface
            if (implementedInterface.IsGenericType)
            {
                foreach (var typeInTheAssembly in typesInTheAssembly)
                {
                    if (typeInTheAssembly.IsClass)
                    {
                        var typeInterfaces = typeInTheAssembly.GetInterfaces();
                        foreach (var typeInterface in typeInterfaces)
                        {
                            if (typeInterface.IsGenericType)
                            {
                                var typeGenericInterface = typeInterface.GetGenericTypeDefinition();
                                var implementedGenericInterface = implementedInterface.GetGenericTypeDefinition();
    
                                if (typeGenericInterface == implementedGenericInterface)
                                {
                                    classesImplementingInterface.Add(typeInTheAssembly);
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                foreach (var typeInTheAssembly in typesInTheAssembly)
                {
                    if (typeInTheAssembly.IsClass)
                    {
                        // if the interface is a non-generic interface
                        if (implementedInterface.IsAssignableFrom(typeInTheAssembly))
                        {
                            classesImplementingInterface.Add(typeInTheAssembly);
                        }
                    }
                }
            }
            return Tuple.Create(true, classesImplementingInterface);
        }
    }
    
    public class DummyClass
    {
    }
    
    public interface IHandleMessageG<T>
    {
    }
    
    public interface IHandleMessage
    {
    }
    
    public interface IMsgXX
    {
    }
    
    public interface IMsgXY
    {
    }
    
    public interface IMsgZZ
    {
    }
    
    public class MessageHandlerXY : IHandleMessageG<IMsgXY>, IHandleMessage, IMsgXX
    {
        public string Handle(string a)
        {
            return "aaa";
        }
    }
    
    public class MessageHandlerZZ : IHandleMessageG<IMsgZZ>, IHandleMessage
    {
        public string Handle(string a)
        {
            return "bbb";
        }
    }
    

    【讨论】:

    • 很棒的工作。适用于 dotnet 2.2。只是建议将assemblyToScan 从单个更改为参数数组params Assembly[] assemblies
    【解决方案3】:

    你可以试试

    openGenericType.IsAssignableFrom(myType.GetGenericTypeDefinition()) 
    

    myType.GetInterfaces().Any(i => i.GetGenericTypeDefinition() = openGenericType)
    

    【讨论】:

      【解决方案4】:

      可以使用以下代码获取所有实现IRepository&lt;&gt;接口的类型:

      List<Type> typesImplementingIRepository = new List<Type>();
      IEnumerable<Type> allTypesInThisAssembly = Assembly.GetExecutingAssembly().GetTypes();
      
      foreach (Type type in allTypesInThisAssembly)
      {
          if (type.GetInterface(typeof(IRepository<>).Name.ToString()) != null)
          {
              typesImplementingIRepository.Add(type);
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2012-01-28
        • 2019-01-20
        • 1970-01-01
        • 2014-07-31
        • 1970-01-01
        • 2021-08-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多