66using System . Collections . Concurrent ;
77using System . Collections . Generic ;
88using System . Linq ;
9+ using System . Linq . Expressions ;
910using System . Reflection ;
1011using System . Text ;
1112using System . Threading . Tasks ;
@@ -14,23 +15,46 @@ namespace Magic.IndexedDb.Helpers
1415{
1516 public struct SearchPropEntry
1617 {
17- public SearchPropEntry ( Dictionary < string , MagicPropertyEntry > _propertyEntries )
18+ public SearchPropEntry ( Dictionary < string , MagicPropertyEntry > _propertyEntries ,
19+ ConstructorInfo ? constructor , ParameterInfo [ ] ? constructorParams )
1820 {
1921 propertyEntries = _propertyEntries ;
2022 jsNameToCsName = new Dictionary < string , string > ( StringComparer . OrdinalIgnoreCase ) ;
23+ ConstructorParameterMappings = new Dictionary < string , int > ( StringComparer . OrdinalIgnoreCase ) ;
2124
2225 foreach ( var entry in propertyEntries )
2326 {
2427 jsNameToCsName [ entry . Value . JsPropertyName ] = entry . Value . CsharpPropertyName ;
2528 }
29+
30+ // Store constructor parameters and their indexes
31+ if ( constructor != null && constructorParams != null )
32+ {
33+ for ( int i = 0 ; i < constructorParams . Length ; i ++ )
34+ {
35+ ConstructorParameterMappings [ constructorParams [ i ] . Name ! ] = i ;
36+ }
37+
38+ // Compile a fast instance creator delegate if there is a parameterized constructor
39+ InstanceCreator = ( args ) => constructor . Invoke ( args ) ;
40+ }
41+ else
42+ {
43+ // If there's no constructor, use parameterless instance creation
44+ InstanceCreator = ( _ ) => Activator . CreateInstance ( _propertyEntries . First ( ) . Value . Property . DeclaringType ! ) ;
45+ }
2646 }
2747
2848 public Dictionary < string , MagicPropertyEntry > propertyEntries { get ; }
2949 public Dictionary < string , string > jsNameToCsName { get ; }
50+
51+ public Dictionary < string , int > ConstructorParameterMappings { get ; } // ✅ Stores constructor parameter indexes
52+ public Func < object ? [ ] , object ? > InstanceCreator { get ; } // ✅ Cached constructor invocation
3053 }
3154
3255
3356
57+
3458 public static class PropertyMappingCache
3559 {
3660 internal static readonly ConcurrentDictionary < string , SearchPropEntry > _propertyCache = new ( ) ;
@@ -58,6 +82,23 @@ public static SearchPropEntry GetTypeOfTProperties(Type type)
5882 throw new Exception ( "Something went very wrong getting GetTypeOfTProperties" ) ;
5983 }
6084
85+ private static readonly ConcurrentDictionary < Type , bool > _simpleTypeCache = new ( ) ;
86+
87+ public static bool IsSimpleType ( Type type )
88+ {
89+ return _simpleTypeCache . GetOrAdd ( type , t =>
90+ t . IsPrimitive ||
91+ t . IsEnum ||
92+ t == typeof ( string ) ||
93+ t == typeof ( decimal ) ||
94+ t == typeof ( DateTime ) ||
95+ t == typeof ( DateTimeOffset ) ||
96+ t == typeof ( Guid ) ||
97+ t == typeof ( Uri ) ||
98+ t == typeof ( TimeSpan ) ) ;
99+ }
100+
101+ /*
61102 public static bool IsSimpleType(Type type)
62103 {
63104 return type.IsPrimitive ||
@@ -69,7 +110,7 @@ public static bool IsSimpleType(Type type)
69110 type == typeof(Guid) ||
70111 type == typeof(Uri) ||
71112 type == typeof(TimeSpan);
72- }
113+ }*/
73114
74115
75116 public static IEnumerable < Type > GetAllNestedComplexTypes ( IEnumerable < PropertyInfo > properties )
@@ -115,7 +156,34 @@ public static IEnumerable<Type> GetAllNestedComplexTypes(IEnumerable<PropertyInf
115156 || type.IsArray); // Arrays are collections too
116157 }*/
117158
159+ private static readonly ConcurrentDictionary < Type , bool > _complexTypeCache = new ( ) ;
160+
118161 public static bool IsComplexType ( Type type )
162+ {
163+ return _complexTypeCache . GetOrAdd ( type , t =>
164+ {
165+ if ( IsSimpleType ( t ) || t == typeof ( string ) )
166+ return false ;
167+
168+ if ( t . IsGenericType )
169+ {
170+ Type genericTypeDef = t . GetGenericTypeDefinition ( ) ;
171+ if ( typeof ( IEnumerable < > ) . IsAssignableFrom ( genericTypeDef ) )
172+ {
173+ return IsComplexType ( t . GetGenericArguments ( ) [ 0 ] ) ;
174+ }
175+ return t . GetGenericArguments ( ) . Any ( IsComplexType ) ;
176+ }
177+
178+ if ( typeof ( IEnumerable ) . IsAssignableFrom ( t ) || t . IsArray )
179+ return false ;
180+
181+ return true ;
182+ } ) ;
183+ }
184+
185+
186+ /*public static bool IsComplexType(Type type)
119187 {
120188 if (IsSimpleType(type) || type == typeof(string))
121189 return false;
@@ -141,7 +209,7 @@ public static bool IsComplexType(Type type)
141209 return false;
142210
143211 return true; // Consider anything else a complex object
144- }
212+ }*/
145213
146214
147215
@@ -336,8 +404,13 @@ internal static void EnsureTypeIsCached(Type type)
336404 propertyEntries [ propertyKey ] = magicEntry ; // Store property entry with string key
337405 }
338406
407+ // 🔥 Extract constructor metadata
408+ var constructor = type . GetConstructors ( ) . FirstOrDefault ( ) ;
409+ var constructorParams = constructor ? . GetParameters ( ) ;
410+
339411 // Cache the properties for this type
340- _propertyCache [ typeKey ] = new SearchPropEntry ( propertyEntries ) ;
412+ _propertyCache [ typeKey ] = new SearchPropEntry ( propertyEntries ,
413+ constructor , constructorParams ?? Array . Empty < ParameterInfo > ( ) ) ;
341414
342415 var complexTypes = GetAllNestedComplexTypes ( newMagicPropertyEntry . Select ( x => x . Property ) ) ;
343416 if ( complexTypes != null && complexTypes . Any ( ) )
0 commit comments