关于c#:获取实现特定开放泛型类型的所有类型

Get all types implementing specific open generic type

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

例如:

1
public interface IUserRepository : IRepository<User>

查找实现IRepository<>的所有类型。

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

这将返回继承泛型基类的所有类型。不是所有继承通用接口的类型。

1
2
3
4
5
6
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;

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

1
2
3
4
5
6
7
8
9
10
11
12
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;
}

在本例中,第二个方法将找到ConcreteUserRepo和IUserRepository:

1
2
3
4
5
6
7
8
9
10
11
public interface ConcreteUserRepo : IUserRepository
{}

public interface IUserRepository : IRepository<User>
{}

public interface IRepository<User>
{}

public class User
{}


解决方案实现时不使用LINQ,搜索通用和非通用接口,将返回类型筛选到类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
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";
    }
}


你可以试试

1
openGenericType.IsAssignableFrom(myType.GetGenericTypeDefinition())

4