1
- using System ;
2
- using System . Collections . Generic ;
3
- using System . Reflection ;
4
- using Soenneker . Extensions . Array . Object ;
1
+ using Soenneker . Extensions . Array . Object ;
5
2
using Soenneker . Extensions . Type . Array ;
6
3
using Soenneker . Reflection . Cache . Constructors . Abstract ;
7
4
using Soenneker . Reflection . Cache . Extensions ;
8
5
using Soenneker . Reflection . Cache . Types ;
6
+ using System ;
7
+ using System . Collections . Frozen ;
8
+ using System . Collections . Generic ;
9
+ using System . Linq . Expressions ;
10
+ using System . Reflection ;
11
+ using System . Runtime . CompilerServices ;
12
+ using System . Threading ;
9
13
10
14
namespace Soenneker . Reflection . Cache . Constructors ;
11
15
12
- ///<inheritdoc cref="ICachedConstructors"/>
16
+ /// <inheritdoc cref="ICachedConstructors"/>
13
17
public sealed class CachedConstructors : ICachedConstructors
14
18
{
15
19
private readonly Lazy < CachedConstructor [ ] > _cachedArray ;
16
- private readonly Lazy < Dictionary < int , CachedConstructor > > _cachedDict ;
17
-
18
- private readonly CachedType _cachedType ;
19
- private readonly CachedTypes _cachedTypes ;
20
-
20
+ private readonly Lazy < FrozenDictionary < int , CachedConstructor > > _cachedDict ;
21
21
private readonly Lazy < ConstructorInfo ? [ ] > _cachedConstructorInfos ;
22
22
23
+ // Fast path for parameterless construction (if available)
24
+ private readonly Lazy < Func < object ? > > _parameterlessActivator ;
25
+
23
26
public CachedConstructors ( CachedType cachedType , CachedTypes cachedTypes , bool threadSafe = true )
24
27
{
25
- _cachedType = cachedType ;
26
- _cachedTypes = cachedTypes ;
28
+ CachedType cachedType1 = cachedType ;
29
+ CachedTypes cachedTypes1 = cachedTypes ;
27
30
28
- _cachedArray = new Lazy < CachedConstructor [ ] > ( ( ) => SetArray ( threadSafe ) , threadSafe ) ;
29
- _cachedDict = new Lazy < Dictionary < int , CachedConstructor > > ( ( ) => SetDict ( threadSafe ) , threadSafe ) ;
30
- _cachedDict = new Lazy < Dictionary < int , CachedConstructor > > ( ( ) => SetDict ( threadSafe ) , threadSafe ) ;
31
+ LazyThreadSafetyMode mode = threadSafe ? LazyThreadSafetyMode . ExecutionAndPublication : LazyThreadSafetyMode . None ;
31
32
32
- _cachedConstructorInfos = new Lazy < ConstructorInfo ? [ ] > ( ( ) => _cachedArray . Value . ToConstructorInfos ( ) , threadSafe ) ;
33
- }
33
+ var constructorInfos = new Lazy < ConstructorInfo [ ] > ( ( ) => cachedType1 . Type ! . GetConstructors ( cachedTypes1 . Options . ConstructorFlags ) , mode ) ;
34
34
35
- public CachedConstructor ? GetCachedConstructor ( Type [ ] ? parameterTypes = null )
36
- {
37
- int key = parameterTypes . ToHashKey ( ) ;
38
- return _cachedDict . Value . GetValueOrDefault ( key ) ;
39
- }
40
-
41
- public ConstructorInfo ? GetConstructor ( Type [ ] ? parameterTypes = null )
42
- {
43
- return GetCachedConstructor ( parameterTypes ) ? . ConstructorInfo ;
44
- }
45
-
46
- private CachedConstructor [ ] SetArray ( bool threadSafe )
47
- {
48
- if ( _cachedDict . IsValueCreated )
35
+ _cachedArray = new Lazy < CachedConstructor [ ] > ( ( ) =>
49
36
{
50
- Dictionary < int , CachedConstructor > . ValueCollection cachedDictValues = _cachedDict . Value . Values ;
51
- var result = new CachedConstructor [ cachedDictValues . Count ] ;
52
- var i = 0 ;
53
-
54
- foreach ( CachedConstructor constructor in cachedDictValues )
37
+ ConstructorInfo [ ] infos = constructorInfos . Value ;
38
+ var result = new CachedConstructor [ infos . Length ] ;
39
+ for ( var i = 0 ; i < infos . Length ; i ++ )
55
40
{
56
- result [ i ++ ] = constructor ;
41
+ result [ i ] = new CachedConstructor ( infos [ i ] , cachedTypes1 , threadSafe ) ;
57
42
}
58
43
59
44
return result ;
60
- }
61
-
62
- ConstructorInfo [ ] constructorInfos = _cachedType . Type ! . GetConstructors ( _cachedTypes . Options . ConstructorFlags ) ;
63
- int length = constructorInfos . Length ;
64
-
65
- var cachedConstructors = new CachedConstructor [ length ] ;
66
-
67
- for ( var i = 0 ; i < length ; i ++ )
68
- {
69
- cachedConstructors [ i ] = new CachedConstructor ( constructorInfos [ i ] , _cachedTypes , threadSafe ) ;
70
- }
71
-
72
- return cachedConstructors ;
73
- }
45
+ } , mode ) ;
74
46
75
- private Dictionary < int , CachedConstructor > SetDict ( bool threadSafe )
76
- {
77
- if ( _cachedArray . IsValueCreated )
47
+ _cachedDict = new Lazy < FrozenDictionary < int , CachedConstructor > > ( ( ) =>
78
48
{
79
- CachedConstructor [ ] cachedArrayValue = _cachedArray . Value ;
80
- int length = cachedArrayValue . Length ;
81
-
82
- var dict = new Dictionary < int , CachedConstructor > ( length ) ;
83
-
84
- for ( var i = 0 ; i < length ; i ++ )
49
+ CachedConstructor [ ] arr = _cachedArray . Value ;
50
+ var dict = new Dictionary < int , CachedConstructor > ( arr . Length ) ;
51
+ for ( var i = 0 ; i < arr . Length ; i ++ )
85
52
{
86
- int key = cachedArrayValue [ i ] . ToHashKey ( ) ;
87
- dict [ key ] = cachedArrayValue [ i ] ;
53
+ dict [ arr [ i ] . ToHashKey ( ) ] = arr [ i ] ; // last-one-wins for duplicate sig hashes
88
54
}
89
55
90
- return dict ;
91
- }
92
-
93
- ConstructorInfo [ ] constructorInfos = _cachedType . Type ! . GetConstructors ( _cachedTypes . Options . ConstructorFlags ) ;
94
- int constructorInfosLength = constructorInfos . Length ;
56
+ return dict . ToFrozenDictionary ( ) ;
57
+ } , mode ) ;
95
58
96
- var constructorsDict = new Dictionary < int , CachedConstructor > ( constructorInfosLength ) ;
59
+ _cachedConstructorInfos = new Lazy < ConstructorInfo ? [ ] > ( ( ) => _cachedArray . Value . ToConstructorInfos ( ) , mode ) ;
97
60
98
- ReadOnlySpan < ConstructorInfo > constructorsSpan = constructorInfos ;
99
-
100
- for ( var i = 0 ; i < constructorInfosLength ; i ++ )
61
+ _parameterlessActivator = new Lazy < Func < object ? > > ( ( ) =>
101
62
{
102
- ConstructorInfo info = constructorsSpan [ i ] ;
103
-
104
- ParameterInfo [ ] parameters = info . GetParameters ( ) ;
105
-
106
- int parametersLength = parameters . Length ;
63
+ Type type = cachedType1 . Type ! ;
64
+ ConstructorInfo ? ctor = type . GetConstructor ( Type . EmptyTypes ) ;
65
+ if ( ctor is null )
66
+ return static ( ) => null ;
107
67
108
- var parameterTypes = new Type [ parametersLength ] ;
109
-
110
- ReadOnlySpan < ParameterInfo > parametersSpan = parameters ;
111
-
112
- for ( var j = 0 ; j < parametersLength ; j ++ )
68
+ try
113
69
{
114
- parameterTypes [ j ] = parametersSpan [ j ] . ParameterType ;
70
+ // Build: () => new T()
71
+ NewExpression newExpr = Expression . New ( ctor ) ;
72
+ Expression < Func < object ? > > lambda = Expression . Lambda < Func < object ? > > ( Expression . Convert ( newExpr , typeof ( object ) ) ) ;
73
+ return lambda . Compile ( ) ;
115
74
}
116
-
117
- int key = parameterTypes . ToHashKey ( ) ;
118
-
119
- constructorsDict [ key ] = new CachedConstructor ( info , _cachedTypes , threadSafe ) ;
120
- }
121
-
122
- return constructorsDict ;
75
+ catch
76
+ {
77
+ return ( ) => Activator . CreateInstance ( type ) ;
78
+ }
79
+ } , mode ) ;
123
80
}
124
81
125
- public CachedConstructor [ ] GetCachedConstructors ( )
82
+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
83
+ public CachedConstructor ? GetCachedConstructor ( Type [ ] ? parameterTypes = null )
126
84
{
127
- return _cachedArray . Value ;
85
+ int key = parameterTypes . ToHashKey ( ) ;
86
+ return _cachedDict . Value . GetValueOrDefault ( key ) ;
128
87
}
129
88
130
- public ConstructorInfo ? [ ] GetConstructors ( )
131
- {
132
- return _cachedConstructorInfos . Value ;
133
- }
89
+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
90
+ public ConstructorInfo ? GetConstructor ( Type [ ] ? parameterTypes = null ) => GetCachedConstructor ( parameterTypes ) ? . ConstructorInfo ;
91
+
92
+ public CachedConstructor [ ] GetCachedConstructors ( ) => _cachedArray . Value ;
93
+
94
+ public ConstructorInfo ? [ ] GetConstructors ( ) => _cachedConstructorInfos . Value ;
134
95
135
96
public object ? CreateInstance ( )
136
97
{
137
- //TODO: One day parameterless invoke of the constructorInfo may be faster than Activator.CreateInstance
138
- return Activator . CreateInstance ( _cachedType . Type ! ) ;
98
+ // Use the cached parameterless activator if present; otherwise null if no default ctor.
99
+ Func < object ? > f = _parameterlessActivator . Value ;
100
+ return f ( ) ;
139
101
}
140
102
141
103
public T ? CreateInstance < T > ( )
142
104
{
143
- return ( T ? ) Activator . CreateInstance ( _cachedType . Type ! ) ;
105
+ object ? obj = CreateInstance ( ) ;
106
+ return obj is null ? default : ( T ? ) obj ;
144
107
}
145
-
108
+
146
109
public object ? CreateInstance ( params object [ ] parameters )
147
110
{
148
111
if ( parameters . Length == 0 )
149
112
return CreateInstance ( ) ;
150
113
114
+ // Avoid a LINQ pass; reuse your extension which is likely optimized.
151
115
Type [ ] parameterTypes = parameters . ToTypes ( ) ;
152
116
153
117
CachedConstructor ? cachedConstructor = GetCachedConstructor ( parameterTypes ) ;
154
-
155
118
return cachedConstructor ? . Invoke ( parameters ) ;
156
119
}
157
120
@@ -163,10 +126,6 @@ public CachedConstructor[] GetCachedConstructors()
163
126
Type [ ] parameterTypes = parameters . ToTypes ( ) ;
164
127
165
128
CachedConstructor ? cachedConstructor = GetCachedConstructor ( parameterTypes ) ;
166
-
167
- if ( cachedConstructor == null )
168
- return default ;
169
-
170
- return cachedConstructor . Invoke < T > ( parameters ) ;
129
+ return cachedConstructor is null ? default : cachedConstructor . Invoke < T > ( parameters ) ;
171
130
}
172
131
}
0 commit comments