@@ -18,19 +18,19 @@ public static class ProxyGenerator
18
18
19
19
private static readonly byte [ ] privateKeyToken = StringToByteArray ( "be96cd2c38ef1005" ) ;
20
20
21
- private static readonly MethodInfo delegate_Combine = typeof ( Delegate ) . GetDeclaredMethod ( "Combine" , new [ ] { typeof ( Delegate ) , typeof ( Delegate ) } ) ;
21
+ private static readonly MethodInfo delegate_Combine = typeof ( Delegate ) . GetDeclaredMethod ( "Combine" , new [ ] { typeof ( Delegate ) , typeof ( Delegate ) } ) ;
22
22
23
- private static readonly MethodInfo delegate_Remove = typeof ( Delegate ) . GetDeclaredMethod ( "Remove" , new [ ] { typeof ( Delegate ) , typeof ( Delegate ) } ) ;
23
+ private static readonly MethodInfo delegate_Remove = typeof ( Delegate ) . GetDeclaredMethod ( "Remove" , new [ ] { typeof ( Delegate ) , typeof ( Delegate ) } ) ;
24
24
25
25
private static readonly EventInfo iNotifyPropertyChanged_PropertyChanged =
26
- typeof ( INotifyPropertyChanged ) . GetRuntimeEvent ( "PropertyChanged" ) ;
26
+ typeof ( INotifyPropertyChanged ) . GetRuntimeEvent ( "PropertyChanged" ) ;
27
27
28
28
private static readonly ConstructorInfo proxyBase_ctor =
29
- typeof ( ProxyBase ) . GetDeclaredConstructor ( new Type [ 0 ] ) ;
29
+ typeof ( ProxyBase ) . GetDeclaredConstructor ( new Type [ 0 ] ) ;
30
30
31
31
private static readonly ModuleBuilder proxyModule = CreateProxyModule ( ) ;
32
32
33
- private static readonly LockingConcurrentDictionary < Type , Type > proxyTypes = new LockingConcurrentDictionary < Type , Type > ( EmitProxy ) ;
33
+ private static readonly LockingConcurrentDictionary < TypeDescription , Type > proxyTypes = new LockingConcurrentDictionary < TypeDescription , Type > ( EmitProxy ) ;
34
34
35
35
private static ModuleBuilder CreateProxyModule ( )
36
36
{
@@ -43,19 +43,19 @@ private static ModuleBuilder CreateProxyModule()
43
43
return builder . DefineDynamicModule ( "AutoMapper.Proxies.emit" ) ;
44
44
}
45
45
46
- private static Type EmitProxy ( Type interfaceType )
46
+ private static Type EmitProxy ( TypeDescription typeDescription )
47
47
{
48
+ var interfaceType = typeDescription . Type ;
49
+ var additionalProperties = typeDescription . AdditionalProperties ;
50
+ var propertyNames = string . Join ( "_" , additionalProperties . Select ( p => p . Name ) ) ;
48
51
string name =
49
- $ "Proxy<{ Regex . Replace ( interfaceType . AssemblyQualifiedName ?? interfaceType . FullName ?? interfaceType . Name , @"[\s,]+" , "_" ) } >";
50
- List < Type > allInterfaces = new List < Type >
51
- {
52
- interfaceType
53
- } ;
52
+ $ "Proxy{ propertyNames } <{ Regex . Replace ( interfaceType . AssemblyQualifiedName ?? interfaceType . FullName ?? interfaceType . Name , @"[\s,]+" , "_" ) } >";
53
+ var allInterfaces = new List < Type > { interfaceType } ;
54
54
allInterfaces . AddRange ( interfaceType . GetTypeInfo ( ) . ImplementedInterfaces ) ;
55
55
Debug . WriteLine ( name , "Emitting proxy type" ) ;
56
56
TypeBuilder typeBuilder = proxyModule . DefineType ( name ,
57
57
TypeAttributes . Class | TypeAttributes . Sealed | TypeAttributes . Public , typeof ( ProxyBase ) ,
58
- allInterfaces . ToArray ( ) ) ;
58
+ interfaceType . IsInterface ? new [ ] { interfaceType } : Type . EmptyTypes ) ;
59
59
ConstructorBuilder constructorBuilder = typeBuilder . DefineConstructor ( MethodAttributes . Public ,
60
60
CallingConventions . Standard , new Type [ 0 ] ) ;
61
61
ILGenerator ctorIl = constructorBuilder . GetILGenerator ( ) ;
@@ -98,12 +98,13 @@ private static Type EmitProxy(Type interfaceType)
98
98
typeBuilder . DefineMethodOverride ( removePropertyChangedMethod ,
99
99
iNotifyPropertyChanged_PropertyChanged . RemoveMethod ) ;
100
100
}
101
- List < PropertyInfo > propertiesToImplement = new List < PropertyInfo > ( ) ;
101
+ var propertiesToImplement = new List < PropertyDescription > ( ) ;
102
102
// first we collect all properties, those with setters before getters in order to enable less specific redundant getters
103
- foreach (
104
- PropertyInfo property in
105
- allInterfaces . Where ( intf => intf != typeof ( INotifyPropertyChanged ) )
106
- . SelectMany ( intf => intf . GetProperties ( ) ) )
103
+ foreach ( var property in
104
+ allInterfaces . Where ( intf => intf != typeof ( INotifyPropertyChanged ) )
105
+ . SelectMany ( intf => intf . GetProperties ( ) )
106
+ . Select ( p => new PropertyDescription ( p ) )
107
+ . Concat ( additionalProperties ) )
107
108
{
108
109
if ( property . CanWrite )
109
110
{
@@ -114,14 +115,14 @@ PropertyInfo property in
114
115
propertiesToImplement . Add ( property ) ;
115
116
}
116
117
}
117
- Dictionary < string , PropertyEmitter > fieldBuilders = new Dictionary < string , PropertyEmitter > ( ) ;
118
- foreach ( PropertyInfo property in propertiesToImplement )
118
+ var fieldBuilders = new Dictionary < string , PropertyEmitter > ( ) ;
119
+ foreach ( var property in propertiesToImplement )
119
120
{
120
121
PropertyEmitter propertyEmitter ;
121
122
if ( fieldBuilders . TryGetValue ( property . Name , out propertyEmitter ) )
122
123
{
123
- if ( ( propertyEmitter . PropertyType != property . PropertyType ) &&
124
- ( ( property . CanWrite ) || ( ! property . PropertyType . IsAssignableFrom ( propertyEmitter . PropertyType ) ) ) )
124
+ if ( ( propertyEmitter . PropertyType != property . Type ) &&
125
+ ( ( property . CanWrite ) || ( ! property . Type . IsAssignableFrom ( propertyEmitter . PropertyType ) ) ) )
125
126
{
126
127
throw new ArgumentException (
127
128
$ "The interface has a conflicting property { property . Name } ",
@@ -132,43 +133,110 @@ PropertyInfo property in
132
133
{
133
134
fieldBuilders . Add ( property . Name ,
134
135
propertyEmitter =
135
- new PropertyEmitter ( typeBuilder , property . Name , property . PropertyType , propertyChangedField ) ) ;
136
- }
137
- if ( property . CanRead )
138
- {
139
- typeBuilder . DefineMethodOverride ( propertyEmitter . GetGetter ( property . PropertyType ) ,
140
- property . GetMethod ) ;
141
- }
142
- if ( property . CanWrite )
143
- {
144
- typeBuilder . DefineMethodOverride ( propertyEmitter . GetSetter ( property . PropertyType ) ,
145
- property . SetMethod ) ;
136
+ new PropertyEmitter ( typeBuilder , property . Name , property . Type , propertyChangedField ) ) ;
146
137
}
147
138
}
148
139
return typeBuilder . CreateType ( ) ;
149
140
}
150
141
151
142
public static Type GetProxyType ( Type interfaceType )
152
143
{
153
- if ( interfaceType == null )
154
- {
155
- throw new ArgumentNullException ( nameof ( interfaceType ) ) ;
156
- }
144
+ var key = new TypeDescription ( interfaceType ) ;
157
145
if ( ! interfaceType . IsInterface ( ) )
158
146
{
159
147
throw new ArgumentException ( "Only interfaces can be proxied" , nameof ( interfaceType ) ) ;
160
148
}
161
- return proxyTypes . GetOrAdd ( interfaceType ) ;
149
+ return proxyTypes . GetOrAdd ( key ) ;
150
+ }
151
+
152
+ public static Type GetSimilarType ( Type sourceType , IEnumerable < PropertyDescription > additionalProperties )
153
+ {
154
+ return proxyTypes . GetOrAdd ( new TypeDescription ( sourceType , additionalProperties ) ) ;
162
155
}
163
156
164
157
private static byte [ ] StringToByteArray ( string hex )
165
158
{
166
159
int numberChars = hex . Length ;
167
- byte [ ] bytes = new byte [ numberChars / 2 ] ;
168
- for ( int i = 0 ; i < numberChars ; i += 2 )
169
- bytes [ i / 2 ] = Convert . ToByte ( hex . Substring ( i , 2 ) , 16 ) ;
160
+ byte [ ] bytes = new byte [ numberChars / 2 ] ;
161
+ for ( int i = 0 ; i < numberChars ; i += 2 )
162
+ bytes [ i / 2 ] = Convert . ToByte ( hex . Substring ( i , 2 ) , 16 ) ;
170
163
return bytes ;
171
164
}
172
165
}
166
+
167
+ public struct TypeDescription : IEquatable < TypeDescription >
168
+ {
169
+ public TypeDescription ( Type type ) : this ( type , PropertyDescription . Empty )
170
+ {
171
+ }
172
+
173
+ public TypeDescription ( Type type , IEnumerable < PropertyDescription > additionalProperties )
174
+ {
175
+ Type = type ?? throw new ArgumentNullException ( nameof ( type ) ) ;
176
+ AdditionalProperties = additionalProperties ? . ToArray ( ) ?? throw new ArgumentNullException ( nameof ( additionalProperties ) ) ;
177
+ }
178
+
179
+ public Type Type { get ; }
180
+
181
+ public PropertyDescription [ ] AdditionalProperties { get ; }
182
+
183
+ public override int GetHashCode ( )
184
+ {
185
+ var hashCode = Type . GetHashCode ( ) ;
186
+ foreach ( var property in AdditionalProperties )
187
+ {
188
+ hashCode = HashCodeCombiner . CombineCodes ( hashCode , property . GetHashCode ( ) ) ;
189
+ }
190
+ return hashCode ;
191
+ }
192
+
193
+ public override bool Equals ( object other ) => other is TypeDescription && Equals ( ( TypeDescription ) other ) ;
194
+
195
+ public bool Equals ( TypeDescription other ) => Type == other . Type && AdditionalProperties . SequenceEqual ( other . AdditionalProperties ) ;
196
+
197
+ public static bool operator == ( TypeDescription left , TypeDescription right ) => left . Equals ( right ) ;
198
+
199
+ public static bool operator != ( TypeDescription left , TypeDescription right ) => ! left . Equals ( right ) ;
200
+ }
201
+
202
+ [ DebuggerDisplay ( "{Name}-{Type.Name}" ) ]
203
+ public struct PropertyDescription : IEquatable < PropertyDescription >
204
+ {
205
+ internal static PropertyDescription [ ] Empty = new PropertyDescription [ 0 ] ;
206
+
207
+ public PropertyDescription ( string name , Type type , bool canWrite = true )
208
+ {
209
+ Name = name ;
210
+ Type = type ;
211
+ CanWrite = canWrite ;
212
+ }
213
+
214
+ public PropertyDescription ( PropertyInfo property )
215
+ {
216
+ Name = property . Name ;
217
+ Type = property . PropertyType ;
218
+ CanWrite = property . CanWrite ;
219
+ }
220
+
221
+ public string Name { get ; }
222
+
223
+ public Type Type { get ; }
224
+
225
+ public bool CanWrite { get ; }
226
+
227
+ public override int GetHashCode ( )
228
+ {
229
+ var code = HashCodeCombiner . Combine ( Name , Type ) ;
230
+ return HashCodeCombiner . CombineCodes ( code , CanWrite . GetHashCode ( ) ) ;
231
+ }
232
+
233
+ public override bool Equals ( object other ) => other is PropertyDescription && Equals ( ( PropertyDescription ) other ) ;
234
+
235
+ public bool Equals ( PropertyDescription other ) => Name == other . Name && Type == other . Type && CanWrite == other . CanWrite ;
236
+
237
+ public static bool operator == ( PropertyDescription left , PropertyDescription right ) => left . Equals ( right ) ;
238
+
239
+ public static bool operator != ( PropertyDescription left , PropertyDescription right ) => ! left . Equals ( right ) ;
240
+ }
173
241
}
174
242
#endif
0 commit comments