1
1
#if ! ( UAP10_0 )
2
+ using System . Collections ;
2
3
using System . Collections . Concurrent ;
3
4
using System . Collections . Generic ;
4
5
using System . Diagnostics ;
@@ -21,26 +22,23 @@ namespace System.Linq.Dynamic.Core
21
22
/// </summary>
22
23
public static class DynamicClassFactory
23
24
{
24
- // EmptyTypes is used to indicate that we are looking for someting without any parameters.
25
- private static readonly Type [ ] EmptyTypes = new Type [ 0 ] ;
26
-
27
25
private static readonly ConcurrentDictionary < string , Type > GeneratedTypes = new ConcurrentDictionary < string , Type > ( ) ;
28
26
29
27
private static readonly ModuleBuilder ModuleBuilder ;
30
28
31
29
// Some objects we cache
32
- private static readonly CustomAttributeBuilder CompilerGeneratedAttributeBuilder = new CustomAttributeBuilder ( typeof ( CompilerGeneratedAttribute ) . GetConstructor ( EmptyTypes ) , new object [ 0 ] ) ;
30
+ private static readonly CustomAttributeBuilder CompilerGeneratedAttributeBuilder = new CustomAttributeBuilder ( typeof ( CompilerGeneratedAttribute ) . GetConstructor ( Type . EmptyTypes ) , new object [ 0 ] ) ;
33
31
private static readonly CustomAttributeBuilder DebuggerBrowsableAttributeBuilder = new CustomAttributeBuilder ( typeof ( DebuggerBrowsableAttribute ) . GetConstructor ( new [ ] { typeof ( DebuggerBrowsableState ) } ) , new object [ ] { DebuggerBrowsableState . Never } ) ;
34
- private static readonly CustomAttributeBuilder DebuggerHiddenAttributeBuilder = new CustomAttributeBuilder ( typeof ( DebuggerHiddenAttribute ) . GetConstructor ( EmptyTypes ) , new object [ 0 ] ) ;
32
+ private static readonly CustomAttributeBuilder DebuggerHiddenAttributeBuilder = new CustomAttributeBuilder ( typeof ( DebuggerHiddenAttribute ) . GetConstructor ( Type . EmptyTypes ) , new object [ 0 ] ) ;
35
33
36
- private static readonly ConstructorInfo ObjectCtor = typeof ( object ) . GetConstructor ( EmptyTypes ) ;
34
+ private static readonly ConstructorInfo ObjectCtor = typeof ( object ) . GetConstructor ( Type . EmptyTypes ) ;
37
35
#if WINDOWS_APP || UAP10_0 || NETSTANDARD
38
36
private static readonly MethodInfo ObjectToString = typeof ( object ) . GetMethod ( "ToString" , BindingFlags . Instance | BindingFlags . Public ) ;
39
37
#else
40
- private static readonly MethodInfo ObjectToString = typeof ( object ) . GetMethod ( "ToString" , BindingFlags . Instance | BindingFlags . Public , null , EmptyTypes , null ) ;
38
+ private static readonly MethodInfo ObjectToString = typeof ( object ) . GetMethod ( "ToString" , BindingFlags . Instance | BindingFlags . Public , null , Type . EmptyTypes , null ) ;
41
39
#endif
42
40
43
- private static readonly ConstructorInfo StringBuilderCtor = typeof ( StringBuilder ) . GetConstructor ( EmptyTypes ) ;
41
+ private static readonly ConstructorInfo StringBuilderCtor = typeof ( StringBuilder ) . GetConstructor ( Type . EmptyTypes ) ;
44
42
#if WINDOWS_APP || UAP10_0 || NETSTANDARD
45
43
private static readonly MethodInfo StringBuilderAppendString = typeof ( StringBuilder ) . GetMethod ( "Append" , new [ ] { typeof ( string ) } ) ;
46
44
private static readonly MethodInfo StringBuilderAppendObject = typeof ( StringBuilder ) . GetMethod ( "Append" , new [ ] { typeof ( object ) } ) ;
@@ -56,7 +54,7 @@ public static class DynamicClassFactory
56
54
private static readonly MethodInfo EqualityComparerEquals = EqualityComparer . GetMethod ( "Equals" , new [ ] { EqualityComparerGenericArgument , EqualityComparerGenericArgument } ) ;
57
55
private static readonly MethodInfo EqualityComparerGetHashCode = EqualityComparer . GetMethod ( "GetHashCode" , new [ ] { EqualityComparerGenericArgument } ) ;
58
56
#else
59
- private static readonly MethodInfo EqualityComparerDefault = EqualityComparer . GetMethod ( "get_Default" , BindingFlags . Static | BindingFlags . Public , null , EmptyTypes , null ) ;
57
+ private static readonly MethodInfo EqualityComparerDefault = EqualityComparer . GetMethod ( "get_Default" , BindingFlags . Static | BindingFlags . Public , null , Type . EmptyTypes , null ) ;
60
58
private static readonly MethodInfo EqualityComparerEquals = EqualityComparer . GetMethod ( "Equals" , BindingFlags . Instance | BindingFlags . Public , null , new [ ] { EqualityComparerGenericArgument , EqualityComparerGenericArgument } , null ) ;
61
59
private static readonly MethodInfo EqualityComparerGetHashCode = EqualityComparer . GetMethod ( "GetHashCode" , BindingFlags . Instance | BindingFlags . Public , null , new [ ] { EqualityComparerGenericArgument } , null ) ;
62
60
#endif
@@ -85,6 +83,71 @@ static DynamicClassFactory()
85
83
ModuleBuilder = assemblyBuilder . DefineDynamicModule ( DynamicModuleName ) ;
86
84
}
87
85
86
+ /// <summary>
87
+ /// Create a GenericComparerType based on the GenericType and an instance of a <see cref="IComparer"/>.
88
+ /// </summary>
89
+ /// <param name="comparerGenericType">The GenericType</param>
90
+ /// <param name="comparerType">The <see cref="IComparer"/> instance</param>
91
+ /// <returns>Type</returns>
92
+ public static Type CreateGenericComparerType ( Type comparerGenericType , Type comparerType )
93
+ {
94
+ Check . NotNull ( comparerGenericType , nameof ( comparerGenericType ) ) ;
95
+ Check . NotNull ( comparerType , nameof ( comparerType ) ) ;
96
+
97
+ var key = $ "{ comparerGenericType . FullName } _{ comparerType . FullName } ";
98
+
99
+ if ( ! GeneratedTypes . TryGetValue ( key , out var type ) )
100
+ {
101
+ // We create only a single class at a time, through this lock
102
+ // Note that this is a variant of the double-checked locking.
103
+ // It is safe because we are using a thread safe class.
104
+ lock ( GeneratedTypes )
105
+ {
106
+ if ( ! GeneratedTypes . TryGetValue ( key , out type ) )
107
+ {
108
+ var compareMethodGeneric = comparerGenericType . GetMethod ( "Compare" ) ;
109
+ var compareMethod = typeof ( IComparer ) . GetMethod ( "Compare" ) ;
110
+ var compareCtor = comparerType . GetConstructor ( Type . EmptyTypes ) ;
111
+
112
+ var typeBuilder = ModuleBuilder . DefineType ( key , TypeAttributes . AnsiClass | TypeAttributes . Public | TypeAttributes . Class | TypeAttributes . AutoLayout , typeof ( object ) ) ;
113
+ typeBuilder . AddInterfaceImplementation ( comparerGenericType ) ;
114
+
115
+ var fieldBuilder = typeBuilder . DefineField ( "_c" , typeof ( IComparer ) , FieldAttributes . Private | FieldAttributes . InitOnly ) ;
116
+
117
+ var constructorBuilder = typeBuilder . DefineConstructor ( MethodAttributes . Public | MethodAttributes . HideBySig , CallingConventions . HasThis , Type . EmptyTypes ) ;
118
+ var constructorIL = constructorBuilder . GetILGenerator ( ) ;
119
+ constructorIL . Emit ( OpCodes . Ldarg_0 ) ;
120
+ constructorIL . Emit ( OpCodes . Call , ObjectCtor ) ;
121
+ constructorIL . Emit ( OpCodes . Ldarg_0 ) ;
122
+ constructorIL . Emit ( OpCodes . Newobj , compareCtor ) ;
123
+ constructorIL . Emit ( OpCodes . Stfld , fieldBuilder ) ;
124
+ constructorIL . Emit ( OpCodes . Ret ) ;
125
+
126
+ var methodBuilder = typeBuilder . DefineMethod (
127
+ compareMethodGeneric . Name ,
128
+ compareMethodGeneric . Attributes & ~ MethodAttributes . Abstract ,
129
+ compareMethodGeneric . CallingConvention ,
130
+ compareMethodGeneric . ReturnType ,
131
+ compareMethodGeneric . GetParameters ( ) . Select ( p => p . ParameterType ) . ToArray ( )
132
+ ) ;
133
+ var methodBuilderIL = methodBuilder . GetILGenerator ( ) ;
134
+ methodBuilderIL . Emit ( OpCodes . Ldarg_0 ) ;
135
+ methodBuilderIL . Emit ( OpCodes . Ldfld , fieldBuilder ) ;
136
+ methodBuilderIL . Emit ( OpCodes . Ldarg_1 ) ;
137
+ methodBuilderIL . Emit ( OpCodes . Box , typeof ( int ) ) ;
138
+ methodBuilderIL . Emit ( OpCodes . Ldarg_2 ) ;
139
+ methodBuilderIL . Emit ( OpCodes . Box , typeof ( int ) ) ;
140
+ methodBuilderIL . Emit ( OpCodes . Callvirt , compareMethod ) ;
141
+ methodBuilderIL . Emit ( OpCodes . Ret ) ;
142
+
143
+ return GeneratedTypes . GetOrAdd ( key , typeBuilder . CreateType ( ) ) ;
144
+ }
145
+ }
146
+ }
147
+
148
+ return type ;
149
+ }
150
+
88
151
/// <summary>
89
152
/// The CreateType method creates a new data class with a given set of public properties and returns the System.Type object for the newly created class. If a data class with an identical sequence of properties has already been created, the System.Type object for this class is returned.
90
153
/// Data classes implement private instance variables and read/write property accessors for the specified properties.Data classes also override the Equals and GetHashCode members to implement by-value equality.
@@ -157,7 +220,7 @@ public static Type CreateType([NotNull] IList<DynamicProperty> properties, bool
157
220
fields [ i ] = tb . DefineField ( $ "<{ names [ i ] } >i__Field", generics [ i ] . AsType ( ) , FieldAttributes . Private | FieldAttributes . InitOnly ) ;
158
221
fields [ i ] . SetCustomAttribute ( DebuggerBrowsableAttributeBuilder ) ;
159
222
160
- PropertyBuilder property = tb . DefineProperty ( names [ i ] , PropertyAttributes . None , CallingConventions . HasThis , generics [ i ] . AsType ( ) , EmptyTypes ) ;
223
+ PropertyBuilder property = tb . DefineProperty ( names [ i ] , PropertyAttributes . None , CallingConventions . HasThis , generics [ i ] . AsType ( ) , Type . EmptyTypes ) ;
161
224
162
225
// getter
163
226
MethodBuilder getter = tb . DefineMethod ( $ "get_{ names [ i ] } ", MethodAttributes . Public | MethodAttributes . HideBySig | MethodAttributes . SpecialName , CallingConventions . HasThis , generics [ i ] . AsType ( ) , null ) ;
@@ -184,7 +247,7 @@ public static Type CreateType([NotNull] IList<DynamicProperty> properties, bool
184
247
}
185
248
186
249
// ToString()
187
- MethodBuilder toString = tb . DefineMethod ( "ToString" , MethodAttributes . Public | MethodAttributes . Virtual | MethodAttributes . HideBySig , CallingConventions . HasThis , typeof ( string ) , EmptyTypes ) ;
250
+ MethodBuilder toString = tb . DefineMethod ( "ToString" , MethodAttributes . Public | MethodAttributes . Virtual | MethodAttributes . HideBySig , CallingConventions . HasThis , typeof ( string ) , Type . EmptyTypes ) ;
188
251
toString . SetCustomAttribute ( DebuggerHiddenAttributeBuilder ) ;
189
252
ILGenerator ilgeneratorToString = toString . GetILGenerator ( ) ;
190
253
ilgeneratorToString . DeclareLocal ( typeof ( StringBuilder ) ) ;
@@ -206,7 +269,7 @@ public static Type CreateType([NotNull] IList<DynamicProperty> properties, bool
206
269
Label equalsLabel = ilgeneratorEquals . DefineLabel ( ) ;
207
270
208
271
// GetHashCode()
209
- MethodBuilder getHashCode = tb . DefineMethod ( "GetHashCode" , MethodAttributes . Public | MethodAttributes . Virtual | MethodAttributes . HideBySig , CallingConventions . HasThis , typeof ( int ) , EmptyTypes ) ;
272
+ MethodBuilder getHashCode = tb . DefineMethod ( "GetHashCode" , MethodAttributes . Public | MethodAttributes . Virtual | MethodAttributes . HideBySig , CallingConventions . HasThis , typeof ( int ) , Type . EmptyTypes ) ;
210
273
getHashCode . SetCustomAttribute ( DebuggerHiddenAttributeBuilder ) ;
211
274
ILGenerator ilgeneratorGetHashCode = getHashCode . GetILGenerator ( ) ;
212
275
ilgeneratorGetHashCode . DeclareLocal ( typeof ( int ) ) ;
@@ -283,7 +346,7 @@ public static Type CreateType([NotNull] IList<DynamicProperty> properties, bool
283
346
if ( createParameterCtor && names . Any ( ) )
284
347
{
285
348
// .ctor default
286
- ConstructorBuilder constructorDef = tb . DefineConstructor ( MethodAttributes . Public | MethodAttributes . HideBySig , CallingConventions . HasThis , EmptyTypes ) ;
349
+ ConstructorBuilder constructorDef = tb . DefineConstructor ( MethodAttributes . Public | MethodAttributes . HideBySig , CallingConventions . HasThis , Type . EmptyTypes ) ;
287
350
constructorDef . SetCustomAttribute ( DebuggerHiddenAttributeBuilder ) ;
288
351
289
352
ILGenerator ilgeneratorConstructorDef = constructorDef . GetILGenerator ( ) ;
0 commit comments