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