7
7
using System . Diagnostics . CodeAnalysis ;
8
8
using System . Linq ;
9
9
using System . Reflection ;
10
+ using System . Runtime . CompilerServices ;
10
11
11
12
namespace Microsoft . AspNetCore . Components . Reflection
12
13
{
14
+ internal readonly struct ObjectWithReferenceEquality : IEquatable < ObjectWithReferenceEquality >
15
+ {
16
+ private readonly object _value ;
17
+
18
+ public ObjectWithReferenceEquality ( object value )
19
+ {
20
+ _value = value ;
21
+ }
22
+
23
+ public override bool Equals ( object ? obj )
24
+ {
25
+ return obj is ObjectWithReferenceEquality other
26
+ ? ReferenceEquals ( _value , other . _value ) : false ;
27
+ }
28
+
29
+ public bool Equals ( [ AllowNull ] ObjectWithReferenceEquality other )
30
+ {
31
+ return ReferenceEquals ( _value , other . _value ) ;
32
+ }
33
+
34
+ public override int GetHashCode ( )
35
+ {
36
+ return RuntimeHelpers . GetHashCode ( _value ) ;
37
+ }
38
+ }
39
+
13
40
internal static class ComponentProperties
14
41
{
15
42
private const BindingFlags _bindablePropertyFlags = BindingFlags . Public | BindingFlags . NonPublic | BindingFlags . Instance | BindingFlags . IgnoreCase ;
@@ -20,36 +47,6 @@ internal static class ComponentProperties
20
47
private readonly static ConcurrentDictionary < Type , WritersForType > _cachedWritersByType
21
48
= new ConcurrentDictionary < Type , WritersForType > ( ) ;
22
49
23
- private static bool TryGetWriter ( WriterEntry [ ] entries , string key , out IPropertySetter value )
24
- {
25
- int minNum = 0 ;
26
- int maxNum = entries . Length - 1 ;
27
- var comparer = StringComparer . Ordinal ;
28
-
29
- while ( minNum <= maxNum )
30
- {
31
- int mid = ( minNum + maxNum ) / 2 ;
32
- ref var entryAtMidpoint = ref entries [ mid ] ;
33
- var comparisonResult = comparer . Compare ( key , entryAtMidpoint . Key ) ;
34
- if ( comparisonResult < 0 )
35
- {
36
- maxNum = mid - 1 ;
37
- }
38
- else if ( comparisonResult > 0 )
39
- {
40
- minNum = mid + 1 ;
41
- }
42
- else
43
- {
44
- value = entryAtMidpoint . Value ;
45
- return true ;
46
- }
47
- }
48
-
49
- value = default ! ;
50
- return false ;
51
- }
52
-
53
50
public static void SetProperties ( in ParameterView parameters , object target )
54
51
{
55
52
if ( target == null )
@@ -72,7 +69,7 @@ public static void SetProperties(in ParameterView parameters, object target)
72
69
{
73
70
var parameterName = parameter . Name ;
74
71
75
- if ( ! TryGetWriter ( writers . WritersByName , parameterName , out var writer ) )
72
+ if ( ! writers . TryGetValue ( parameterName , out var writer ) )
76
73
{
77
74
// Case 1: There is nowhere to put this value.
78
75
ThrowForUnknownIncomingParameterName ( targetType , parameterName ) ;
@@ -113,7 +110,7 @@ public static void SetProperties(in ParameterView parameters, object target)
113
110
isCaptureUnmatchedValuesParameterSetExplicitly = true ;
114
111
}
115
112
116
- if ( TryGetWriter ( writers . WritersByName , parameterName , out var writer ) )
113
+ if ( writers . TryGetValue ( parameterName , out var writer ) )
117
114
{
118
115
if ( ! writer . Cascading && parameter . Cascading )
119
116
{
@@ -278,7 +275,7 @@ private class WritersForType
278
275
{
279
276
public WritersForType ( Type targetType )
280
277
{
281
- var writersByNameDict = new Dictionary < string , IPropertySetter > ( ) ;
278
+ var writersByNameDict = new Dictionary < string , IPropertySetter > ( StringComparer . OrdinalIgnoreCase ) ;
282
279
foreach ( var propertyInfo in GetCandidateBindableProperties ( targetType ) )
283
280
{
284
281
var parameterAttribute = propertyInfo . GetCustomAttribute < ParameterAttribute > ( ) ;
@@ -328,23 +325,27 @@ public WritersForType(Type targetType)
328
325
}
329
326
}
330
327
331
- WritersByName = writersByNameDict
332
- . Select ( kv => new WriterEntry { Key = kv . Key , Value = kv . Value } )
333
- . OrderBy ( e => e . Key )
334
- . ToArray ( ) ;
328
+ _writersByName = writersByNameDict ;
335
329
}
336
330
337
- public WriterEntry [ ] WritersByName { get ; }
331
+ private readonly Dictionary < string , IPropertySetter > _writersByName ;
332
+ private readonly Dictionary < ObjectWithReferenceEquality , IPropertySetter > _cachedLookups = new Dictionary < ObjectWithReferenceEquality , IPropertySetter > ( ) ;
338
333
339
334
public IPropertySetter ? CaptureUnmatchedValuesWriter { get ; }
340
335
341
336
public string ? CaptureUnmatchedValuesPropertyName { get ; }
342
- }
343
337
344
- private struct WriterEntry
345
- {
346
- public string Key ;
347
- public IPropertySetter Value ;
338
+ public bool TryGetValue ( string parameterName , out IPropertySetter setter )
339
+ {
340
+ var key = new ObjectWithReferenceEquality ( parameterName ) ;
341
+ if ( ! _cachedLookups . TryGetValue ( key , out setter ! ) )
342
+ {
343
+ _writersByName . TryGetValue ( parameterName , out setter ! ) ;
344
+ _cachedLookups . Add ( key , setter ) ;
345
+ }
346
+
347
+ return setter != null ;
348
+ }
348
349
}
349
350
}
350
351
}
0 commit comments