private static Type EmitProxy(TypeDescription typeDescription) { var interfaceType = typeDescription.Type; var additionalProperties = typeDescription.AdditionalProperties; var propertyNames = string.Join("_", additionalProperties.Select(p => p.Name)); var typeName = $"Proxy_{interfaceType.FullName}_{propertyNames}_{typeDescription.GetHashCode()}"; var allInterfaces = new List <Type> { interfaceType }; allInterfaces.AddRange(interfaceType.GetTypeInfo().ImplementedInterfaces); Debug.WriteLine(typeName, "Emitting proxy type"); TypeBuilder typeBuilder = proxyModule.DefineType(typeName, 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()); }
private static Type CreateProxyType(Type interfaceType) { if (!interfaceType.IsInterface()) { throw new ArgumentException("Only interfaces can be proxied", nameof(interfaceType)); } string name = $"Proxy<{Regex.Replace(interfaceType.AssemblyQualifiedName ?? interfaceType.FullName ?? interfaceType.Name, @"[\s,]+", "_")}>"; List <Type> 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), allInterfaces.ToArray()); 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.AddMethod); typeBuilder.DefineMethodOverride(removePropertyChangedMethod, iNotifyPropertyChanged_PropertyChanged.RemoveMethod); } List <PropertyInfo> propertiesToImplement = new List <PropertyInfo>(); // first we collect all properties, those with setters before getters in order to enable less specific redundant getters foreach ( PropertyInfo property in allInterfaces.Where(intf => intf != typeof(INotifyPropertyChanged)) .SelectMany(intf => intf.GetProperties())) { if (property.CanWrite) { propertiesToImplement.Insert(0, property); } else { propertiesToImplement.Add(property); } } Dictionary <string, PropertyEmitter> fieldBuilders = new Dictionary <string, PropertyEmitter>(); foreach (PropertyInfo property in propertiesToImplement) { PropertyEmitter propertyEmitter; if (fieldBuilders.TryGetValue(property.Name, out propertyEmitter)) { if ((propertyEmitter.PropertyType != property.PropertyType) && ((property.CanWrite) || (!property.PropertyType.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.Name, property.PropertyType, propertyChangedField)); } if (property.CanRead) { typeBuilder.DefineMethodOverride(propertyEmitter.GetGetter(property.PropertyType), property.GetMethod); } if (property.CanWrite) { typeBuilder.DefineMethodOverride(propertyEmitter.GetSetter(property.PropertyType), property.SetMethod); } } return(typeBuilder.CreateType()); }
private static Type EmitProxy(Type interfaceType) { string name = $"Proxy<{Regex.Replace(interfaceType.AssemblyQualifiedName ?? interfaceType.FullName ?? interfaceType.Name, @"[\s,]+", "_")}>"; List<Type> 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), allInterfaces.ToArray()); 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.AddMethod); typeBuilder.DefineMethodOverride(removePropertyChangedMethod, iNotifyPropertyChanged_PropertyChanged.RemoveMethod); } List<PropertyInfo> propertiesToImplement = new List<PropertyInfo>(); // first we collect all properties, those with setters before getters in order to enable less specific redundant getters foreach( PropertyInfo property in allInterfaces.Where(intf => intf != typeof(INotifyPropertyChanged)) .SelectMany(intf => intf.GetProperties())) { if(property.CanWrite) { propertiesToImplement.Insert(0, property); } else { propertiesToImplement.Add(property); } } Dictionary<string, PropertyEmitter> fieldBuilders = new Dictionary<string, PropertyEmitter>(); foreach(PropertyInfo property in propertiesToImplement) { PropertyEmitter propertyEmitter; if(fieldBuilders.TryGetValue(property.Name, out propertyEmitter)) { if((propertyEmitter.PropertyType != property.PropertyType) && ((property.CanWrite) || (!property.PropertyType.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.Name, property.PropertyType, propertyChangedField)); } if(property.CanRead) { typeBuilder.DefineMethodOverride(propertyEmitter.GetGetter(property.PropertyType), property.GetMethod); } if(property.CanWrite) { typeBuilder.DefineMethodOverride(propertyEmitter.GetSetter(property.PropertyType), property.SetMethod); } } return typeBuilder.CreateType(); }