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());
        }
Exemple #2
0
        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());
        }
Exemple #3
0
 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();
 }