private static Type CreateProxyType(Type interfaceType) { if (!interfaceType.IsInterface) { throw new ArgumentException("Only interfaces can be proxied", "interfaceType"); } string name = string.Format("Proxy<{0}>", Regex.Replace(interfaceType.AssemblyQualifiedName ?? interfaceType.FullName ?? interfaceType.Name, @"[\s,]+", "_")); List<Type> allInterfaces = new List<Type> { interfaceType }; allInterfaces.AddRange(interfaceType.GetInterfaces()); 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, Type.EmptyTypes); 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()); } 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(string.Format("The interface has a conflicting property {0}", property.Name), "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.GetGetMethod()); } if (property.CanWrite) { typeBuilder.DefineMethodOverride(propertyEmitter.GetSetter(property.PropertyType), property.GetSetMethod()); } } return typeBuilder.CreateType(); }
private static Type CreateProxyType(Type interfaceType) { if (!interfaceType.IsInterface) { throw new ArgumentException("Only interfaces can be proxied", "interfaceType"); } string name = string.Format("Proxy<{0}>", Regex.Replace(interfaceType.AssemblyQualifiedName ?? interfaceType.FullName ?? interfaceType.Name, @"[\s,]+", "_")); List <Type> allInterfaces = new List <Type> { interfaceType }; allInterfaces.AddRange(interfaceType.GetInterfaces()); 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, Type.EmptyTypes); 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()); } 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(string.Format("The interface has a conflicting property {0}", property.Name), "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.GetGetMethod()); } if (property.CanWrite) { typeBuilder.DefineMethodOverride(propertyEmitter.GetSetter(property.PropertyType), property.GetSetMethod()); } } return(typeBuilder.CreateType()); }