in tools/AutoMapper/Execution/ProxyGenerator.cs [49:143]
private static Type EmitProxy(TypeDescription typeDescription)
{
var interfaceType = typeDescription.Type;
var additionalProperties = typeDescription.AdditionalProperties;
var propertyNames = string.Join("_", additionalProperties.Select(p => p.Name));
string name =
$"Proxy{propertyNames}<{Regex.Replace(interfaceType.AssemblyQualifiedName ?? interfaceType.FullName ?? interfaceType.Name, @"[\s,]+", "_")}>";
var allInterfaces = new List<Type> { interfaceType };
allInterfaces.AddRange(interfaceType.GetTypeInfo().ImplementedInterfaces);
Debug.WriteLine(name, "Emitting proxy type");
TypeBuilder typeBuilder = proxyModule.DefineType(name,
TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.Public, typeof(ProxyBase),
interfaceType.IsInterface() ? new[] { interfaceType } : new Type[0]);
ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public,
CallingConventions.Standard, new Type[0]);
ILGenerator ctorIl = constructorBuilder.GetILGenerator();
ctorIl.Emit(OpCodes.Ldarg_0);
ctorIl.Emit(OpCodes.Call, proxyBase_ctor);
ctorIl.Emit(OpCodes.Ret);
FieldBuilder propertyChangedField = null;
if(typeof(INotifyPropertyChanged).IsAssignableFrom(interfaceType))
{
propertyChangedField = typeBuilder.DefineField("PropertyChanged", typeof(PropertyChangedEventHandler),
FieldAttributes.Private);
MethodBuilder addPropertyChangedMethod = typeBuilder.DefineMethod("add_PropertyChanged",
MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName |
MethodAttributes.NewSlot | MethodAttributes.Virtual, typeof(void),
new[] { typeof(PropertyChangedEventHandler) });
ILGenerator addIl = addPropertyChangedMethod.GetILGenerator();
addIl.Emit(OpCodes.Ldarg_0);
addIl.Emit(OpCodes.Dup);
addIl.Emit(OpCodes.Ldfld, propertyChangedField);
addIl.Emit(OpCodes.Ldarg_1);
addIl.Emit(OpCodes.Call, delegate_Combine);
addIl.Emit(OpCodes.Castclass, typeof(PropertyChangedEventHandler));
addIl.Emit(OpCodes.Stfld, propertyChangedField);
addIl.Emit(OpCodes.Ret);
MethodBuilder removePropertyChangedMethod = typeBuilder.DefineMethod("remove_PropertyChanged",
MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName |
MethodAttributes.NewSlot | MethodAttributes.Virtual, typeof(void),
new[] { typeof(PropertyChangedEventHandler) });
ILGenerator removeIl = removePropertyChangedMethod.GetILGenerator();
removeIl.Emit(OpCodes.Ldarg_0);
removeIl.Emit(OpCodes.Dup);
removeIl.Emit(OpCodes.Ldfld, propertyChangedField);
removeIl.Emit(OpCodes.Ldarg_1);
removeIl.Emit(OpCodes.Call, delegate_Remove);
removeIl.Emit(OpCodes.Castclass, typeof(PropertyChangedEventHandler));
removeIl.Emit(OpCodes.Stfld, propertyChangedField);
removeIl.Emit(OpCodes.Ret);
typeBuilder.DefineMethodOverride(addPropertyChangedMethod,
iNotifyPropertyChanged_PropertyChanged.GetAddMethod());
typeBuilder.DefineMethodOverride(removePropertyChangedMethod,
iNotifyPropertyChanged_PropertyChanged.GetRemoveMethod());
}
var propertiesToImplement = new List<PropertyDescription>();
// first we collect all properties, those with setters before getters in order to enable less specific redundant getters
foreach(var property in
allInterfaces.Where(intf => intf != typeof(INotifyPropertyChanged))
.SelectMany(intf => intf.GetProperties())
.Select(p => new PropertyDescription(p))
.Concat(additionalProperties))
{
if(property.CanWrite)
{
propertiesToImplement.Insert(0, property);
}
else
{
propertiesToImplement.Add(property);
}
}
var fieldBuilders = new Dictionary<string, PropertyEmitter>();
foreach(var property in propertiesToImplement)
{
PropertyEmitter propertyEmitter;
if(fieldBuilders.TryGetValue(property.Name, out propertyEmitter))
{
if((propertyEmitter.PropertyType != property.Type) &&
((property.CanWrite) || (!property.Type.IsAssignableFrom(propertyEmitter.PropertyType))))
{
throw new ArgumentException(
$"The interface has a conflicting property {property.Name}",
nameof(interfaceType));
}
}
else
{
fieldBuilders.Add(property.Name,
propertyEmitter =
new PropertyEmitter(typeBuilder, property, propertyChangedField));
}
}
return typeBuilder.CreateType();
}