获取实现特定开放泛型类型的所有类型

Posted

技术标签:

【中文标题】获取实现特定开放泛型类型的所有类型【英文标题】:Get all types implementing specific open generic type 【发布时间】:2012-01-28 13:08:21 【问题描述】:

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

例如:

public interface IUserRepository : IRepository<User>

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

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

  ...

【问题讨论】:

【参考方案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:***.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://***.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://***.com/questions/7889228/how-to-prevent-reflectiontypeloadexception-when-calling-assembly-gettypes
    // return all types implementing a generic interface
    // http://***.com/questions/33694960/find-all-types-implementing-a-certain-generic-interface-with-specific-t-type
    // http://***.com/questions/8645430/get-all-types-implementing-specific-open-generic-type
    // http://***.com/questions/1121834/finding-out-if-a-type-implements-a-generic-interface
    // http://***.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);
    

【讨论】:

以上是关于获取实现特定开放泛型类型的所有类型的主要内容,如果未能解决你的问题,请参考以下文章

180530-反射获取泛型类的实际参数

c# 泛型学习

Java泛型

Java泛型

如何获取java泛型的参数类型

Java 无类型泛型类,删除它们的函数泛型类型