Пример #1
0
        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 } : Type.EmptyTypes);
            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);
            }
            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());
        }
Пример #2
0
        private static Type EmitProxy(TypeDescription typeDescription)
        {
            var interfaceType = typeDescription.Type;
            var typeBuilder   = GenerateType();

            GenerateConstructor();
            FieldBuilder propertyChangedField = null;

            if (typeof(INotifyPropertyChanged).IsAssignableFrom(interfaceType))
            {
                GeneratePropertyChanged();
            }
            GenerateFields();
            return(typeBuilder.CreateTypeInfo().AsType());

            TypeBuilder GenerateType()
            {
                var       propertyNames     = string.Join("_", typeDescription.AdditionalProperties.Select(p => p.Name));
                var       typeName          = $"Proxy_{interfaceType.FullName}_{typeDescription.GetHashCode()}_{propertyNames}";
                const int MaxTypeNameLength = 1023;

                typeName = typeName.Substring(0, Math.Min(MaxTypeNameLength, typeName.Length));
                Debug.WriteLine(typeName, "Emitting proxy type");
                return(ProxyModule.DefineType(typeName,
                                              TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.Public, typeof(ProxyBase),
                                              interfaceType.IsInterface ? new[] { interfaceType } : Type.EmptyTypes));
            }

            void GeneratePropertyChanged()
            {
                propertyChangedField = typeBuilder.DefineField(PropertyChanged.Name, typeof(PropertyChangedEventHandler), FieldAttributes.Private);
                EventAccessor(PropertyChanged.AddMethod, DelegateCombine);
                EventAccessor(PropertyChanged.RemoveMethod, DelegateRemove);
            }

            void EventAccessor(MethodInfo method, MethodInfo delegateMethod)
            {
                var eventAccessor = typeBuilder.DefineMethod(method.Name,
                                                             MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName |
                                                             MethodAttributes.NewSlot | MethodAttributes.Virtual, typeof(void),
                                                             new[] { typeof(PropertyChangedEventHandler) });
                var addIl = eventAccessor.GetILGenerator();

                addIl.Emit(OpCodes.Ldarg_0);
                addIl.Emit(OpCodes.Dup);
                addIl.Emit(OpCodes.Ldfld, propertyChangedField);
                addIl.Emit(OpCodes.Ldarg_1);
                addIl.Emit(OpCodes.Call, delegateMethod);
                addIl.Emit(OpCodes.Castclass, typeof(PropertyChangedEventHandler));
                addIl.Emit(OpCodes.Stfld, propertyChangedField);
                addIl.Emit(OpCodes.Ret);
                typeBuilder.DefineMethodOverride(eventAccessor, method);
            }

            void GenerateFields()
            {
                var fieldBuilders = new Dictionary <string, PropertyEmitter>();

                foreach (var property in PropertiesToImplement())
                {
                    if (fieldBuilders.TryGetValue(property.Name, out var 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, new PropertyEmitter(typeBuilder, property, propertyChangedField));
                    }
                }
            }

            List <PropertyDescription> PropertiesToImplement()
            {
                var propertiesToImplement = new List <PropertyDescription>();
                var allInterfaces         = new List <Type>(interfaceType.GetInterfaces())
                {
                    interfaceType
                };

                // 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(typeDescription.AdditionalProperties))
                {
                    if (property.CanWrite)
                    {
                        propertiesToImplement.Insert(0, property);
                    }
                    else
                    {
                        propertiesToImplement.Add(property);
                    }
                }
                return(propertiesToImplement);
            }

            void GenerateConstructor()
            {
                var constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes);
                var ctorIl             = constructorBuilder.GetILGenerator();

                ctorIl.Emit(OpCodes.Ldarg_0);
                ctorIl.Emit(OpCodes.Call, ProxyBaseCtor);
                ctorIl.Emit(OpCodes.Ret);
            }
        }