@@ -16,21 +16,21 @@ public sealed class CachedMethods : ICachedMethods
16
16
private readonly CachedType _cachedType ;
17
17
private readonly CachedTypes _cachedTypes ;
18
18
19
- // Build all three artifacts in one go, once.
19
+ // Build all artifacts in one go, once.
20
20
private readonly Lazy < BuiltCache > _built ;
21
21
22
22
private readonly bool _threadSafe ;
23
23
24
24
private sealed class BuiltCache
25
25
{
26
26
public readonly CachedMethod [ ] Methods ;
27
- public readonly FrozenDictionary < int , CachedMethod > Index ;
27
+ public readonly FrozenDictionary < string , CachedMethod [ ] > MethodsByName ;
28
28
public readonly MethodInfo ? [ ] MethodInfos ;
29
29
30
- public BuiltCache ( CachedMethod [ ] methods , FrozenDictionary < int , CachedMethod > index , MethodInfo ? [ ] infos )
30
+ public BuiltCache ( CachedMethod [ ] methods , FrozenDictionary < string , CachedMethod [ ] > methodsByName , MethodInfo ? [ ] infos )
31
31
{
32
32
Methods = methods ;
33
- Index = index ;
33
+ MethodsByName = methodsByName ;
34
34
MethodInfos = infos ;
35
35
}
36
36
}
@@ -51,27 +51,39 @@ private BuiltCache BuildAll()
51
51
int count = methodInfos . Length ;
52
52
53
53
var methods = new CachedMethod [ count ] ;
54
- var dict = new Dictionary < int , CachedMethod > ( count ) ;
54
+ var byName = new Dictionary < string , List < CachedMethod > > ( StringComparer . Ordinal ) ;
55
55
56
56
for ( var i = 0 ; i < count ; i ++ )
57
57
{
58
58
var cm = new CachedMethod ( methodInfos [ i ] , _cachedTypes , _threadSafe ) ;
59
59
methods [ i ] = cm ;
60
- dict . Add ( cm . ToHashKey ( ) , cm ) ;
60
+
61
+ string name = cm . Name ! ;
62
+ if ( ! byName . TryGetValue ( name , out List < CachedMethod > ? list ) )
63
+ {
64
+ list = new List < CachedMethod > ( ) ;
65
+ byName [ name ] = list ;
66
+ }
67
+ list . Add ( cm ) ;
61
68
}
62
69
63
- // Freeze for faster, allocation-friendly lookups
64
- FrozenDictionary < int , CachedMethod > frozen = dict . ToFrozenDictionary ( ) ;
70
+ // Freeze name map
71
+ var frozenByName = new Dictionary < string , CachedMethod [ ] > ( byName . Count , StringComparer . Ordinal ) ;
72
+ foreach ( KeyValuePair < string , List < CachedMethod > > kvp in byName )
73
+ {
74
+ frozenByName [ kvp . Key ] = kvp . Value . ToArray ( ) ;
75
+ }
76
+
77
+ FrozenDictionary < string , CachedMethod [ ] > methodsByName = frozenByName . ToFrozenDictionary ( StringComparer . Ordinal ) ;
65
78
66
79
// MethodInfos array without extra enumerations
67
80
var infos = new MethodInfo ? [ count ] ;
68
-
69
81
for ( var i = 0 ; i < count ; i ++ )
70
82
{
71
83
infos [ i ] = methods [ i ] . MethodInfo ;
72
84
}
73
85
74
- return new BuiltCache ( methods , frozen , infos ) ;
86
+ return new BuiltCache ( methods , methodsByName , infos ) ;
75
87
}
76
88
77
89
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
@@ -89,21 +101,82 @@ private BuiltCache BuildAll()
89
101
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
90
102
public CachedMethod ? GetCachedMethod ( string name )
91
103
{
92
- int key = ReflectionCacheUtil . GetCacheKeyForMethod ( name ) ;
93
- return _built . Value . Index . GetValueOrDefault ( key ) ;
104
+ if ( ! _built . Value . MethodsByName . TryGetValue ( name , out CachedMethod [ ] ? candidates ) || candidates . Length == 0 )
105
+ return null ;
106
+
107
+ // If there is a single candidate, return it; otherwise prefer parameterless
108
+ if ( candidates . Length == 1 )
109
+ return candidates [ 0 ] ;
110
+
111
+ for ( var i = 0 ; i < candidates . Length ; i ++ )
112
+ {
113
+ ParameterInfo [ ] ? ps = candidates [ i ] . GetParameters ( ) ;
114
+ if ( ps . Length == 0 )
115
+ return candidates [ i ] ;
116
+ }
117
+
118
+ // Fallback: first candidate
119
+ return candidates [ 0 ] ;
94
120
}
95
121
96
122
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
97
123
public CachedMethod ? GetCachedMethod ( string name , Type [ ] parameterTypes )
98
124
{
99
- int key = ReflectionCacheUtil . GetCacheKeyForMethod ( name , parameterTypes ) ;
100
- return _built . Value . Index . GetValueOrDefault ( key ) ;
125
+ if ( ! _built . Value . MethodsByName . TryGetValue ( name , out CachedMethod [ ] ? candidates ) || candidates . Length == 0 )
126
+ return null ;
127
+
128
+ for ( var i = 0 ; i < candidates . Length ; i ++ )
129
+ {
130
+ ParameterInfo [ ] ps = candidates [ i ] . GetParameters ( ) ;
131
+ if ( ps . Length != parameterTypes . Length )
132
+ continue ;
133
+
134
+ var match = true ;
135
+ for ( var j = 0 ; j < ps . Length ; j ++ )
136
+ {
137
+ if ( ! ReferenceEquals ( ps [ j ] . ParameterType , parameterTypes [ j ] ) )
138
+ {
139
+ match = false ;
140
+ break ;
141
+ }
142
+ }
143
+
144
+ if ( match )
145
+ return candidates [ i ] ;
146
+ }
147
+
148
+ return null ;
101
149
}
102
150
103
151
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
104
152
public CachedMethod ? GetCachedMethod ( string name , CachedType [ ] cachedParameterTypes )
105
153
{
106
- int key = ReflectionCacheUtil . GetCacheKeyForMethodWithCachedParameterTypes ( name , cachedParameterTypes ) ;
107
- return _built . Value . Index . GetValueOrDefault ( key ) ;
154
+ if ( ! _built . Value . MethodsByName . TryGetValue ( name , out CachedMethod [ ] ? candidates ) || candidates . Length == 0 )
155
+ return null ;
156
+
157
+ int len = cachedParameterTypes ? . Length ?? 0 ;
158
+
159
+ for ( var i = 0 ; i < candidates . Length ; i ++ )
160
+ {
161
+ ParameterInfo [ ] ps = candidates [ i ] . GetParameters ( ) ;
162
+ if ( ps . Length != len )
163
+ continue ;
164
+
165
+ var match = true ;
166
+ for ( var j = 0 ; j < len ; j ++ )
167
+ {
168
+ Type ? t = cachedParameterTypes [ j ] . Type ;
169
+ if ( ! ReferenceEquals ( ps [ j ] . ParameterType , t ) )
170
+ {
171
+ match = false ;
172
+ break ;
173
+ }
174
+ }
175
+
176
+ if ( match )
177
+ return candidates [ i ] ;
178
+ }
179
+
180
+ return null ;
108
181
}
109
182
}
0 commit comments