@@ -21,7 +21,7 @@ namespace System.Linq.Dynamic.Core
21
21
public static class DynamicClassFactory
22
22
{
23
23
// EmptyTypes is used to indicate that we are looking for someting without any parameters.
24
- private readonly static Type [ ] EmptyTypes = new Type [ 0 ] ;
24
+ private static readonly Type [ ] EmptyTypes = new Type [ 0 ] ;
25
25
26
26
private static readonly ConcurrentDictionary < string , Type > GeneratedTypes = new ConcurrentDictionary < string , Type > ( ) ;
27
27
@@ -98,24 +98,20 @@ public static Type CreateType([NotNull] IList<DynamicProperty> properties, bool
98
98
{
99
99
Check . HasNoNulls ( properties , nameof ( properties ) ) ;
100
100
101
- var types = properties . Select ( p => p . Type ) . ToArray ( ) ;
102
- var names = properties . Select ( p => p . Name ) . ToArray ( ) ;
101
+ Type [ ] types = properties . Select ( p => p . Type ) . ToArray ( ) ;
102
+ string [ ] names = properties . Select ( p => p . Name ) . ToArray ( ) ;
103
103
104
- // Anonymous classes are generics based. The generic classes are distinguished by number of parameters and name of parameters.
105
- // The specific types of the parameters are the generic arguments.
106
- // We recreate this by creating a fullName composed of all the property names, separated by a "|".
107
- string fullName = string . Join ( "|" , names . Select ( Escape ) . ToArray ( ) ) ;
104
+ string key = GenerateKey ( properties , createParameterCtor ) ;
108
105
109
106
Type type ;
110
-
111
- if ( ! GeneratedTypes . TryGetValue ( fullName , out type ) )
107
+ if ( ! GeneratedTypes . TryGetValue ( key , out type ) )
112
108
{
113
109
// We create only a single class at a time, through this lock
114
110
// Note that this is a variant of the double-checked locking.
115
111
// It is safe because we are using a thread safe class.
116
112
lock ( GeneratedTypes )
117
113
{
118
- if ( ! GeneratedTypes . TryGetValue ( fullName , out type ) )
114
+ if ( ! GeneratedTypes . TryGetValue ( key , out type ) )
119
115
{
120
116
int index = Interlocked . Increment ( ref _index ) ;
121
117
@@ -350,7 +346,7 @@ public static Type CreateType([NotNull] IList<DynamicProperty> properties, bool
350
346
351
347
type = tb . CreateType ( ) ;
352
348
353
- type = GeneratedTypes . GetOrAdd ( fullName + "|_" + ( createParameterCtor ? "1" : "0" ) , type ) ;
349
+ type = GeneratedTypes . GetOrAdd ( key , type ) ;
354
350
}
355
351
}
356
352
}
@@ -363,6 +359,20 @@ public static Type CreateType([NotNull] IList<DynamicProperty> properties, bool
363
359
return type ;
364
360
}
365
361
362
+ /// <summary>
363
+ /// Generates the key.
364
+ /// Anonymous classes are generics based. The generic classes are distinguished by number of parameters and name of parameters. The specific types of the parameters are the generic arguments.
365
+ /// </summary>
366
+ /// <param name="dynamicProperties">The dynamic propertys.</param>
367
+ /// <param name="createParameterCtor">if set to <c>true</c> [create parameter ctor].</param>
368
+ /// <returns></returns>
369
+ private static string GenerateKey ( IEnumerable < DynamicProperty > dynamicProperties , bool createParameterCtor )
370
+ {
371
+ // We recreate this by creating a fullName composed of all the property names and types, separated by a "|".
372
+ // And append and extra field depending on createParameterCtor.
373
+ return string . Format ( "{0}_{1}" , string . Join ( "|" , dynamicProperties . Select ( p => Escape ( p . Name ) + "~" + p . Type . FullName ) . ToArray ( ) ) , createParameterCtor ? "c" : string . Empty ) ;
374
+ }
375
+
366
376
private static string Escape ( string str )
367
377
{
368
378
// We escape the \ with \\, so that we can safely escape the "|" (that we use as a separator) with "\|"
0 commit comments