1313
1414namespace Magic . IndexedDb . Helpers
1515{
16+
1617 public struct SearchPropEntry
1718 {
18- public SearchPropEntry ( Dictionary < string , MagicPropertyEntry > _propertyEntries ,
19- ConstructorInfo ? constructor , ParameterInfo [ ] ? constructorParams )
19+ public SearchPropEntry ( Type type , Dictionary < string , MagicPropertyEntry > _propertyEntries , ConstructorInfo [ ] constructors )
2020 {
2121 propertyEntries = _propertyEntries ;
2222 jsNameToCsName = new Dictionary < string , string > ( StringComparer . OrdinalIgnoreCase ) ;
@@ -27,37 +27,62 @@ public SearchPropEntry(Dictionary<string, MagicPropertyEntry> _propertyEntries,
2727 jsNameToCsName [ entry . Value . JsPropertyName ] = entry . Value . CsharpPropertyName ;
2828 }
2929
30- // Store constructor parameters and their indexes
31- if ( constructor != null && constructorParams != null )
30+ // 🔥 Pick the best constructor: Prefer a parameterized one, else fallback to parameterless
31+ var constructor = constructors . OrderByDescending ( c => c . GetParameters ( ) . Length ) . FirstOrDefault ( ) ;
32+ Constructor = constructor ; // ✅ Assign to instance variable
33+ HasConstructorParameters = constructor != null && constructor . GetParameters ( ) . Length > 0 ;
34+
35+ // 🔥 Cache constructor parameter mappings
36+ if ( HasConstructorParameters )
3237 {
33- for ( int i = 0 ; i < constructorParams . Length ; i ++ )
38+ var parameters = constructor . GetParameters ( ) ;
39+ for ( int i = 0 ; i < parameters . Length ; i ++ )
3440 {
35- ConstructorParameterMappings [ constructorParams [ i ] . Name ! ] = i ;
41+ ConstructorParameterMappings [ parameters [ i ] . Name ! ] = i ;
3642 }
43+ }
44+
45+ // 🔥 Store constructor in a local variable before using in lambda (Fix for struct issue)
46+ var localConstructor = constructor ;
3747
38- // Compile a fast instance creator delegate if there is a parameterized constructor
39- InstanceCreator = ( args ) => constructor . Invoke ( args ) ;
48+ // 🔥 Cache fast instance creator
49+ if ( localConstructor != null )
50+ {
51+ InstanceCreator = ( args ) => localConstructor . Invoke ( args ) ;
4052 }
4153 else
4254 {
43- // If there's no constructor, use parameterless instance creation
44- InstanceCreator = ( _ ) => Activator . CreateInstance ( _propertyEntries . First ( ) . Value . Property . DeclaringType ! ) ;
55+ // 🚀 Use default constructor if no valid parameterized constructor is found
56+ InstanceCreator = ( _ ) => IsInstantiable ( type ) ? Activator . CreateInstance ( type ) : throw new InvalidOperationException ( $ "Cannot instantiate abstract/interface type { type . FullName } " ) ;
4557 }
4658 }
4759
60+ public ConstructorInfo ? Constructor { get ; } // ✅ Stores the most relevant constructor
61+ public bool HasConstructorParameters { get ; } // ✅ Cached flag to avoid checking length
62+ public Func < object ? [ ] , object ? > InstanceCreator { get ; } // ✅ Cached instance creator
63+
4864 public Dictionary < string , MagicPropertyEntry > propertyEntries { get ; }
4965 public Dictionary < string , string > jsNameToCsName { get ; }
50-
5166 public Dictionary < string , int > ConstructorParameterMappings { get ; } // ✅ Stores constructor parameter indexes
52- public Func < object ? [ ] , object ? > InstanceCreator { get ; } // ✅ Cached constructor invocation
67+
68+ /// <summary>
69+ /// Determines whether a type can be instantiated.
70+ /// </summary>
71+ private static bool IsInstantiable ( Type type )
72+ {
73+ return ! ( type . IsAbstract || type . IsInterface || type . IsGenericTypeDefinition ) ;
74+ }
5375 }
5476
5577
5678
5779
80+
81+
82+
5883 public static class PropertyMappingCache
5984 {
60- internal static readonly ConcurrentDictionary < string , SearchPropEntry > _propertyCache = new ( ) ;
85+ internal static readonly ConcurrentDictionary < Type , SearchPropEntry > _propertyCache = new ( ) ;
6186
6287
6388 public static MagicPropertyEntry GetPrimaryKeyOfType ( Type type )
@@ -75,42 +100,38 @@ public static MagicPropertyEntry GetPrimaryKeyOfType(Type type)
75100 public static SearchPropEntry GetTypeOfTProperties ( Type type )
76101 {
77102 EnsureTypeIsCached ( type ) ;
78- if ( _propertyCache . TryGetValue ( type . FullName ! , out var properties ) )
103+ if ( _propertyCache . TryGetValue ( type ! , out var properties ) )
79104 {
80105 return properties ;
81106 }
82107 throw new Exception ( "Something went very wrong getting GetTypeOfTProperties" ) ;
83108 }
84109
85- private static readonly ConcurrentDictionary < Type , bool > _simpleTypeCache = new ( ) ;
110+ private static readonly HashSet < Type > _simpleTypes = new ( )
111+ {
112+ typeof ( string ) , typeof ( decimal ) , typeof ( DateTime ) , typeof ( DateTimeOffset ) ,
113+ typeof ( Guid ) , typeof ( Uri ) , typeof ( TimeSpan )
114+ } ;
86115
87116 public static bool IsSimpleType ( Type type )
88117 {
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 ) ) ;
118+ return type . IsPrimitive || type . IsEnum || _simpleTypes . Contains ( type ) ;
99119 }
100120
101- /*
102- public static bool IsSimpleType(Type type)
103- {
104- return type.IsPrimitive ||
105- type.IsEnum ||
106- type == typeof(string) ||
107- type == typeof(decimal) ||
108- type == typeof(DateTime) ||
109- type == typeof(DateTimeOffset) ||
110- type == typeof(Guid) ||
111- type == typeof(Uri) ||
112- type == typeof(TimeSpan);
113- }*/
121+
122+ /*
123+ public static bool IsSimpleType(Type type)
124+ {
125+ return type.IsPrimitive ||
126+ type.IsEnum ||
127+ type == typeof(string) ||
128+ type == typeof(decimal) ||
129+ type == typeof(DateTime) ||
130+ type == typeof(DateTimeOffset) ||
131+ type == typeof(Guid) ||
132+ type == typeof(Uri) ||
133+ type == typeof(TimeSpan);
134+ }*/
114135
115136
116137 public static IEnumerable < Type > GetAllNestedComplexTypes ( IEnumerable < PropertyInfo > properties )
@@ -147,16 +168,16 @@ public static IEnumerable<Type> GetAllNestedComplexTypes(IEnumerable<PropertyInf
147168 return complexTypes ;
148169 }
149170
150- /* public static bool IsComplexType(Type type)
171+ public static bool IsComplexType ( Type type )
151172 {
152173 return ! ( IsSimpleType ( type )
153174 || type == typeof ( string )
154175 || typeof ( IEnumerable ) . IsAssignableFrom ( type ) // Non-generic IEnumerable
155176 || ( type . IsGenericType && typeof ( IEnumerable < > ) . IsAssignableFrom ( type . GetGenericTypeDefinition ( ) ) ) // Generic IEnumerable<T>
156177 || type . IsArray ) ; // Arrays are collections too
157- }*/
178+ }
158179
159- private static readonly ConcurrentDictionary < Type , bool > _complexTypeCache = new ( ) ;
180+ /* private static readonly ConcurrentDictionary<Type, bool> _complexTypeCache = new();
160181
161182 public static bool IsComplexType(Type type)
162183 {
@@ -180,7 +201,7 @@ public static bool IsComplexType(Type type)
180201
181202 return true;
182203 });
183- }
204+ }*/
184205
185206
186207 /*public static bool IsComplexType(Type type)
@@ -231,7 +252,7 @@ public static string GetCsharpPropertyName(string jsPropertyName, Type type)
231252
232253 try
233254 {
234- if ( _propertyCache . TryGetValue ( typeKey , out var search ) )
255+ if ( _propertyCache . TryGetValue ( type , out var search ) )
235256 {
236257 return search . GetCsharpPropertyName ( jsPropertyName ) ;
237258 }
@@ -291,7 +312,7 @@ public static string GetJsPropertyName(string csharpPropertyName, Type type)
291312
292313 try
293314 {
294- if ( _propertyCache . TryGetValue ( typeKey , out var properties ) &&
315+ if ( _propertyCache . TryGetValue ( type , out var properties ) &&
295316 properties . propertyEntries . TryGetValue ( csharpPropertyName , out var entry ) )
296317 {
297318 return entry . JsPropertyName ;
@@ -323,7 +344,7 @@ public static MagicPropertyEntry GetPropertyEntry(string propertyName, Type type
323344
324345 try
325346 {
326- if ( _propertyCache . TryGetValue ( typeKey , out var properties ) &&
347+ if ( _propertyCache . TryGetValue ( type , out var properties ) &&
327348 properties . propertyEntries . TryGetValue ( propertyName , out var entry ) )
328349 {
329350 return entry ;
@@ -364,10 +385,10 @@ internal static void EnsureTypeIsCached<T>()
364385
365386 internal static void EnsureTypeIsCached ( Type type )
366387 {
367- string typeKey = type . FullName ! ;
388+ // string typeKey = type.FullName!;
368389
369390 // Avoid re-registering types if the typeKey already exists
370- if ( _propertyCache . ContainsKey ( typeKey ) )
391+ if ( _propertyCache . ContainsKey ( type ) )
371392 return ;
372393
373394 // Ensure schema metadata is cached
@@ -405,12 +426,11 @@ internal static void EnsureTypeIsCached(Type type)
405426 }
406427
407428 // 🔥 Extract constructor metadata
408- var constructor = type . GetConstructors ( ) . FirstOrDefault ( ) ;
409- var constructorParams = constructor ? . GetParameters ( ) ;
429+ var constructors = type . GetConstructors ( ) ;
410430
411431 // Cache the properties for this type
412- _propertyCache [ typeKey ] = new SearchPropEntry ( propertyEntries ,
413- constructor , constructorParams ?? Array . Empty < ParameterInfo > ( ) ) ;
432+ _propertyCache [ type ] = new SearchPropEntry ( type , propertyEntries ,
433+ constructors ) ;
414434
415435 var complexTypes = GetAllNestedComplexTypes ( newMagicPropertyEntry . Select ( x => x . Property ) ) ;
416436 if ( complexTypes != null && complexTypes . Any ( ) )
0 commit comments