Skip to content

Commit 55e54ca

Browse files
authored
Merge pull request AutoMapper#2131 from lbargaoanu/LetClause
Let clause
2 parents 625eb39 + fef85cc commit 55e54ca

28 files changed

+804
-171
lines changed

src/AutoMapper/Execution/ProxyGenerator.cs

Lines changed: 108 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,19 @@ public static class ProxyGenerator
1818

1919
private static readonly byte[] privateKeyToken = StringToByteArray("be96cd2c38ef1005");
2020

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) });
2222

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) });
2424

2525
private static readonly EventInfo iNotifyPropertyChanged_PropertyChanged =
26-
typeof (INotifyPropertyChanged).GetRuntimeEvent("PropertyChanged");
26+
typeof(INotifyPropertyChanged).GetRuntimeEvent("PropertyChanged");
2727

2828
private static readonly ConstructorInfo proxyBase_ctor =
29-
typeof (ProxyBase).GetDeclaredConstructor(new Type[0]);
29+
typeof(ProxyBase).GetDeclaredConstructor(new Type[0]);
3030

3131
private static readonly ModuleBuilder proxyModule = CreateProxyModule();
3232

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);
3434

3535
private static ModuleBuilder CreateProxyModule()
3636
{
@@ -43,19 +43,19 @@ private static ModuleBuilder CreateProxyModule()
4343
return builder.DefineDynamicModule("AutoMapper.Proxies.emit");
4444
}
4545

46-
private static Type EmitProxy(Type interfaceType)
46+
private static Type EmitProxy(TypeDescription typeDescription)
4747
{
48+
var interfaceType = typeDescription.Type;
49+
var additionalProperties = typeDescription.AdditionalProperties;
50+
var propertyNames = string.Join("_", additionalProperties.Select(p => p.Name));
4851
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 };
5454
allInterfaces.AddRange(interfaceType.GetTypeInfo().ImplementedInterfaces);
5555
Debug.WriteLine(name, "Emitting proxy type");
5656
TypeBuilder typeBuilder = proxyModule.DefineType(name,
5757
TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.Public, typeof(ProxyBase),
58-
allInterfaces.ToArray());
58+
interfaceType.IsInterface ? new[] { interfaceType } : Type.EmptyTypes);
5959
ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public,
6060
CallingConventions.Standard, new Type[0]);
6161
ILGenerator ctorIl = constructorBuilder.GetILGenerator();
@@ -98,12 +98,13 @@ private static Type EmitProxy(Type interfaceType)
9898
typeBuilder.DefineMethodOverride(removePropertyChangedMethod,
9999
iNotifyPropertyChanged_PropertyChanged.RemoveMethod);
100100
}
101-
List<PropertyInfo> propertiesToImplement = new List<PropertyInfo>();
101+
var propertiesToImplement = new List<PropertyDescription>();
102102
// 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))
107108
{
108109
if(property.CanWrite)
109110
{
@@ -114,14 +115,14 @@ PropertyInfo property in
114115
propertiesToImplement.Add(property);
115116
}
116117
}
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)
119120
{
120121
PropertyEmitter propertyEmitter;
121122
if(fieldBuilders.TryGetValue(property.Name, out propertyEmitter))
122123
{
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))))
125126
{
126127
throw new ArgumentException(
127128
$"The interface has a conflicting property {property.Name}",
@@ -132,43 +133,110 @@ PropertyInfo property in
132133
{
133134
fieldBuilders.Add(property.Name,
134135
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));
146137
}
147138
}
148139
return typeBuilder.CreateType();
149140
}
150141

151142
public static Type GetProxyType(Type interfaceType)
152143
{
153-
if(interfaceType == null)
154-
{
155-
throw new ArgumentNullException(nameof(interfaceType));
156-
}
144+
var key = new TypeDescription(interfaceType);
157145
if(!interfaceType.IsInterface())
158146
{
159147
throw new ArgumentException("Only interfaces can be proxied", nameof(interfaceType));
160148
}
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));
162155
}
163156

164157
private static byte[] StringToByteArray(string hex)
165158
{
166159
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);
170163
return bytes;
171164
}
172165
}
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+
}
173241
}
174242
#endif

src/AutoMapper/ProfileMap.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ private static void ApplyBaseMaps(TypeMapRegistry typeMapRegistry, TypeMap deriv
228228
foreach (var baseMap in currentMap.IncludedBaseTypes.Select(typeMapRegistry.GetTypeMap).Where(baseMap => baseMap != null))
229229
{
230230
baseMap.IncludeDerivedTypes(currentMap.SourceType, currentMap.DestinationType);
231-
derivedMap.ApplyInheritedMap(baseMap);
231+
derivedMap.AddInheritedMap(baseMap);
232232
ApplyBaseMaps(typeMapRegistry, derivedMap, baseMap);
233233
}
234234
}
@@ -237,7 +237,7 @@ private void ApplyDerivedMaps(TypeMapRegistry typeMapRegistry, TypeMap baseMap,
237237
{
238238
foreach (var inheritedTypeMap in typeMap.IncludedDerivedTypes.Select(typeMapRegistry.GetTypeMap).Where(map => map != null))
239239
{
240-
inheritedTypeMap.ApplyInheritedMap(baseMap);
240+
inheritedTypeMap.AddInheritedMap(baseMap);
241241
ApplyDerivedMaps(typeMapRegistry, baseMap, inheritedTypeMap);
242242
}
243243
}

src/AutoMapper/PropertyMap.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public PropertyMap(PropertyMap inheritedMappedProperty, TypeMap typeMap)
4848
public LambdaExpression CustomResolver { get; set; }
4949
public LambdaExpression Condition { get; set; }
5050
public LambdaExpression PreCondition { get; set; }
51-
public LambdaExpression CustomExpression { get; private set; }
51+
public LambdaExpression CustomExpression { get; set; }
5252
public bool UseDestinationValue { get; set; }
5353
public bool ExplicitExpansion { get; set; }
5454
public object NullSubstitute { get; set; }

0 commit comments

Comments
 (0)