1
+ using System ;
2
+ using System . Linq ;
3
+ using System . Collections . Generic ;
4
+ using UnityEditor ;
5
+ using System . Reflection ;
6
+
7
+ namespace MackySoft . SerializeReferenceExtensions . Editor
8
+ {
9
+ public static class TypeSearch
10
+ {
11
+
12
+ #if UNITY_2023_2_OR_NEWER
13
+ static readonly Dictionary < Type , List < Type > > m_TypeCache = new Dictionary < Type , List < Type > > ( ) ;
14
+ #endif
15
+
16
+ public static IEnumerable < Type > GetTypes ( Type baseType )
17
+ {
18
+ #if UNITY_2023_2_OR_NEWER
19
+ // NOTE: This is a workaround for Unity 2023.2 and later.
20
+ // 2023.2 because SerializeReference supports generic type instances and because the behaviour is stable.
21
+ if ( baseType . IsGenericType )
22
+ {
23
+ return GetTypesWithGeneric ( baseType ) ;
24
+ }
25
+ else
26
+ {
27
+ return GetTypesUsingTypeCache ( baseType ) ;
28
+ }
29
+ #else
30
+ return GetTypesWithGeneric ( baseType ) ;
31
+ #endif
32
+ }
33
+
34
+ static IEnumerable < Type > GetTypesUsingTypeCache ( Type baseType )
35
+ {
36
+ return TypeCache . GetTypesDerivedFrom ( baseType )
37
+ . Append ( baseType )
38
+ . Where ( IsValidType ) ;
39
+ }
40
+
41
+ #if UNITY_2023_2_OR_NEWER
42
+ static IEnumerable < Type > GetTypesWithGeneric ( Type baseType )
43
+ {
44
+ if ( m_TypeCache . TryGetValue ( baseType , out List < Type > result ) )
45
+ {
46
+ return result ;
47
+ }
48
+
49
+ result = new List < Type > ( ) ;
50
+ Type genericTypeDefinition = null ;
51
+ Type [ ] targetTypeArguments = null ;
52
+ Type [ ] genericTypeParameters = null ;
53
+
54
+ if ( baseType . IsGenericType )
55
+ {
56
+ genericTypeDefinition = baseType . GetGenericTypeDefinition ( ) ;
57
+ targetTypeArguments = baseType . GetGenericArguments ( ) ;
58
+ genericTypeParameters = genericTypeDefinition . GetGenericArguments ( ) ;
59
+ }
60
+ else
61
+ {
62
+ genericTypeDefinition = baseType ;
63
+ targetTypeArguments = Type . EmptyTypes ;
64
+ genericTypeParameters = Type . EmptyTypes ;
65
+ }
66
+
67
+ IEnumerable < Type > types = AppDomain . CurrentDomain . GetAssemblies ( )
68
+ . SelectMany ( x => x . GetTypes ( ) )
69
+ . Where ( IsValidType ) ;
70
+
71
+ foreach ( Type type in types )
72
+ {
73
+ Type [ ] interfaceTypes = type . GetInterfaces ( ) ;
74
+ foreach ( Type interfaceType in interfaceTypes )
75
+ {
76
+ if ( ! interfaceType . IsGenericType || interfaceType . GetGenericTypeDefinition ( ) != genericTypeDefinition )
77
+ {
78
+ continue ;
79
+ }
80
+
81
+ Type [ ] sourceTypeArguments = interfaceType . GetGenericArguments ( ) ;
82
+
83
+ bool allParametersMatch = true ;
84
+
85
+ for ( int i = 0 ; i < genericTypeParameters . Length ; i ++ )
86
+ {
87
+ var variance = genericTypeParameters [ i ] . GenericParameterAttributes & GenericParameterAttributes . VarianceMask ;
88
+
89
+ Type sourceTypeArgument = sourceTypeArguments [ i ] ;
90
+ Type targetTypeArgument = targetTypeArguments [ i ] ;
91
+
92
+ if ( variance == GenericParameterAttributes . Contravariant )
93
+ {
94
+ if ( ! sourceTypeArgument . IsAssignableFrom ( targetTypeArgument ) )
95
+ {
96
+ allParametersMatch = false ;
97
+ break ;
98
+ }
99
+ }
100
+ else if ( variance == GenericParameterAttributes . Covariant )
101
+ {
102
+ if ( ! targetTypeArgument . IsAssignableFrom ( sourceTypeArgument ) )
103
+ {
104
+ allParametersMatch = false ;
105
+ break ;
106
+ }
107
+ }
108
+ else
109
+ {
110
+ if ( sourceTypeArgument != targetTypeArgument )
111
+ {
112
+ allParametersMatch = false ;
113
+ break ;
114
+ }
115
+ }
116
+ }
117
+
118
+ if ( allParametersMatch )
119
+ {
120
+ result . Add ( type ) ;
121
+ break ;
122
+ }
123
+ }
124
+ }
125
+
126
+ m_TypeCache . Add ( baseType , result ) ;
127
+ return result ;
128
+ }
129
+ #endif
130
+
131
+ static bool IsValidType ( Type type )
132
+ {
133
+ return
134
+ ( type . IsPublic || type . IsNestedPublic || type . IsNestedPrivate ) &&
135
+ ! type . IsAbstract &&
136
+ ! type . IsGenericType &&
137
+ ! typeof ( UnityEngine . Object ) . IsAssignableFrom ( type ) &&
138
+ Attribute . IsDefined ( type , typeof ( SerializableAttribute ) ) &&
139
+ ! Attribute . IsDefined ( type , typeof ( HideInTypeMenuAttribute ) ) ;
140
+ }
141
+ }
142
+ }
0 commit comments