/// <summary>
 ///     Constructs type derived from baseType, implementing interfaceTypes, and overriding TBaseType virtual members if
 ///     overrideVirtual is true.
 /// </summary>
 /// <param name="implementer">Implementation provider for implementation.</param>
 /// <param name="baseType">Base type to derive from.</param>
 /// <param name="interfaceTypes">Type of interfaces to implement.</param>
 /// <param name="excludeInterfaces">Will exclude implementation of this interfaces.</param>
 /// <param name="overrideVirtual">If true, additionally overrides virtual members.</param>
 /// <returns>Constructed type.</returns>
 public static Type ConstructType(IPropertyImplementer implementer, Type baseType, Type[] interfaceTypes,
                                  Type[] excludeInterfaces, bool overrideVirtual = false)
 {
     lock (syncRoot)
     {
         return(ConstructType(implementer, baseType, interfaceTypes, (IEnumerable <Type>)excludeInterfaces,
                              overrideVirtual));
     }
 }
        private static Type ConstructType(IPropertyImplementer implementer, Type baseType, Type[] implementInterfaces,
                                          IEnumerable <Type> excludeTypes, bool overrideVirtual = false)
        {
            var interfaceNames = string.Join("+", implementInterfaces.Select(t => t.Name).ToArray());
            var moduleBuilder  =
                AssemblyBuilder.DefineDynamicModule(string.Format("{0}DerivedFrom{1}ImplenentedBy{2}",
                                                                  interfaceNames, baseType.Name,
                                                                  implementer.GetType().Name));
            // Set the class to be public and sealed
            TypeAttributes typeAttributes =
                TypeAttributes.Class | TypeAttributes.Public;


            var typeBuilder = moduleBuilder.DefineType(string.Format("{1}${0}", interfaceNames, baseType.Name),
                                                       typeAttributes, baseType, implementInterfaces);

            implementer.BeginEmit(typeBuilder);


            foreach (
                var constructor in
                baseType.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
            {
                if (!constructor.IsPrivate)
                {
                    var constructorBuilder = typeBuilder.DefineConstructor(constructor.Attributes,
                                                                           constructor.CallingConvention,
                                                                           constructor.GetParameters().Select(p => p.ParameterType).ToArray());

                    var ilGen = constructorBuilder.GetILGenerator();


                    ilGen.Emit(OpCodes.Jmp, constructor);
                }
            }

            var implementedTypes = new HashSet <Type>(excludeTypes);

            foreach (var type in implementInterfaces)
            {
                if (!type.IsInterface)
                {
                    throw new ArgumentException("Cant implement Type other then interface.");
                }
                GenerateInterfaceMethod(implementer, type, typeBuilder, implementedTypes);
            }
            if (overrideVirtual)
            {
                OverrideVirtualMethod(implementer, baseType, typeBuilder, implementedTypes);
            }
            implementer.EndEmit();

            return(typeBuilder.CreateType());
        }
        private static void ImplementSetter(IPropertyImplementer implementer, TypeBuilder typeBuilder,
                                            PropertyInfo propertyInfo, MethodInfo setMethod)
        {
            // create a new builder for the method in the interface
            MethodBuilder methodBuilder = typeBuilder.DefineMethod(
                string.Format("{0}.{1}", setMethod.DeclaringType.Name, setMethod.Name),
                MethodAttributes.Private | MethodAttributes.NewSlot | MethodAttributes.HideBySig |
                MethodAttributes.Virtual | MethodAttributes.Final,
                CallingConventions.Standard);

            methodBuilder.SetParameters(propertyInfo.PropertyType);
            methodBuilder.SetReturnType(typeof(void));

            #region ( "Implementing Get Method IL Code" )

            implementer.ImplementSetter(methodBuilder, propertyInfo);

            typeBuilder.DefineMethodOverride(methodBuilder, setMethod);

            #endregion
        }
        private static void OverrideVirtualMethod(IPropertyImplementer implementer, Type type, TypeBuilder typeBuilder,
                                                  HashSet <Type> implemented)
        {
            if (implemented.Contains(type) | type == typeof(object))
            {
                return;
            }

            foreach (
                var propertyInfo in
                type.GetProperties(BindingFlags.GetProperty | BindingFlags.SetProperty | BindingFlags.Public |
                                   BindingFlags.Instance | BindingFlags.DeclaredOnly))
            {
                if (propertyInfo.CanRead)
                {
                    MethodInfo getMethod = propertyInfo.GetGetMethod();
                    if (getMethod.IsVirtual && !getMethod.IsFinal)
                    {
                        //exclude overridden methods
                        if (getMethod.GetBaseDefinition() == getMethod)
                        {
                            ImplementGetter(implementer, typeBuilder, propertyInfo, getMethod);
                        }
                    }
                }
                if (propertyInfo.CanWrite)
                {
                    MethodInfo setMethod = propertyInfo.GetSetMethod();
                    if (setMethod.IsVirtual && !setMethod.IsFinal)
                    {
                        //exclude overridden method
                        if (setMethod.GetBaseDefinition() == setMethod)
                        {
                            ImplementSetter(implementer, typeBuilder, propertyInfo, setMethod);
                        }
                    }
                }
            }
            OverrideVirtualMethod(implementer, type.BaseType, typeBuilder, implemented);
        }
        private static void GenerateInterfaceMethod(IPropertyImplementer implementer, Type interfaceType,
                                                    TypeBuilder typeBuilder, HashSet <Type> implemented)
        {
            if (implemented.Contains(interfaceType))
            {
                return;
            }
            foreach (var propertyInfo in interfaceType.GetProperties())
            {
                //if(propertyInfo.DeclaringType == propertyInfo.ReflectedType)
                //{
                if (propertyInfo.CanRead)
                {
                    MethodInfo getMethod = propertyInfo.GetGetMethod();
                    if (getMethod.IsVirtual && !getMethod.IsFinal)
                    {
                        // create a new builder for the method in the interface
                        ImplementGetter(implementer, typeBuilder, propertyInfo, getMethod);
                    }
                }
                if (propertyInfo.CanWrite)
                {
                    MethodInfo setMethod = propertyInfo.GetSetMethod();
                    if (setMethod.IsVirtual && !setMethod.IsFinal)
                    {
                        // create a new builder for the method in the interface
                        ImplementSetter(implementer, typeBuilder, propertyInfo, setMethod);
                    }
                }
                //}
            }

            foreach (Type parentType in interfaceType.GetInterfaces())
            {
                GenerateInterfaceMethod(implementer, parentType, typeBuilder, implemented);
            }

            implemented.Add(interfaceType);
        }
 /// <summary>
 ///     Constructs type derived from baseType, implementing interfaceType, and overriding TBaseType virtual members if
 ///     overrideVirtual is true.
 /// </summary>
 /// <param name="implementer">Implementation provider for implementation.</param>
 /// <param name="baseType">Base type to derive from.</param>
 /// <param name="interfaceType">Type of interface to implement.</param>
 /// <param name="overrideVirtual">If true, additionally overrides virtual members.</param>
 /// <returns>Constructed type.</returns>
 public static Type ConstructType(IPropertyImplementer implementer, Type baseType, Type interfaceType,
                                  bool overrideVirtual = false)
 {
     return(ConstructType(implementer, baseType, new[] { interfaceType }, overrideVirtual));
 }