private static void CreatePropertySetterDelegate(Builder builder, PropertyBuilderInfo member, Method propertySetter)
        {
            // If we don't have a backing field and we don't have a setter and getter
            // don't bother creating a setter delegate
            if (member.Property.BackingField == null && propertySetter == null)
            {
                return;
            }

            if (member.Property.BackingField == null && member.Property.Getter != null && member.Property.Setter != null)
            {
                var getter = member.Property.Getter.Copy();
                var setter = member.Property.Setter.Copy();

                CreateSetterDelegate(builder, propertySetter, member.Property.ReturnType,
                                     x => x.Call(getter.IsStatic ? null : Crumb.This, getter),
                                     (coder, value) => coder.Call(setter.IsStatic ? null : Crumb.This, setter, value()));
            }
            else if (member.Property.BackingField != null && !member.Property.BackingField.FieldType.IsGenericType)
            {
                CreateSetterDelegate(builder, propertySetter, member.Property.BackingField.FieldType,
                                     x => x.Load(member.Property.BackingField) as ICode,
                                     (coder, value) => coder.Assign(member.Property.BackingField).Set(value()));
            }
            else if (member.Property.BackingField == null && member.Property.Setter != null)
            {
                var methodSetter = member.Property.Setter.Copy();
                propertySetter.NewCode().Call(methodSetter.IsStatic ? null : Crumb.This, methodSetter, Crumb.GetParameter(0)).Return().Replace();
            }
            else if (member.Property.BackingField == null && member.Property.Getter != null)
            {
                // This shouldn't be a thing
            }
            else
            {
                propertySetter.NewCode().Assign(member.Property.BackingField).Set(Crumb.GetParameter(0)).Return().Replace();
            }
        }
Exemplo n.º 2
0
        private Method CreateAssigningMethod(BuilderType anonSource, BuilderType anonTarget, BuilderType anonTargetInterface, Method method)
        {
            var name         = $"<{counter++}>f__Anon_Assign";
            var assignMethod = method.OriginType.CreateMethod(Modifiers.PrivateStatic, anonTarget, name, anonSource);

            assignMethod.NewCode()
            .Context(x =>
            {
                var resultVar = x.GetReturnVariable();
                x.Assign(resultVar).Set(x.NewCode().NewObj(anonTarget.ParameterlessContructor));

                foreach (var property in anonSource.Properties)
                {
                    try
                    {
                        var targetProperty = anonTarget.GetProperty(property.Name);
                        if (property.ReturnType.Fullname != targetProperty.ReturnType.Fullname)
                        {
                            this.Log(LogTypes.Error, property, $"The property '{property.Name}' does not have the expected return type. Is: {property.ReturnType.Fullname} Expected: {targetProperty.ReturnType.Fullname}");
                            continue;
                        }
                        x.Load(resultVar).Callvirt(targetProperty.Setter, x.NewCode().Load(Crumb.GetParameter(0)).Callvirt(property.Getter));
                    }
                    catch (MethodNotFoundException)
                    {
                        this.Log(LogTypes.Warning, anonTarget, $"The property '{property.Name}' does not exist in '{anonTarget.Name}'");
                    }
                }

                x.Load(resultVar).Return();
            })
            .Replace();

            assignMethod.CustomAttributes.AddEditorBrowsableAttribute(EditorBrowsableState.Never);

            return(assignMethod);
        }
        private static void CreateSetterDelegate(Builder builder, Method setterDelegateMethod, BuilderType propertyType,
                                                 Func <ICode, ICode> loadValue, Func <ICode, Func <object>, ICode> setValue)
        {
            var extensions = new __Extensions();
            var iList      = new __IList();
            var setterCode = setterDelegateMethod.NewCode();

            if (propertyType.ParameterlessContructor != null && propertyType.ParameterlessContructor.IsPublic)
            {
                loadValue(setterCode).IsNull().Then(y => setValue(y, () => setterCode.NewCode().NewObj(propertyType.ParameterlessContructor)));
            }

            // Only this if the property implements idisposable
            if (propertyType.Implements(typeof(IDisposable)))
            {
                setterCode.Call(extensions.TryDisposeInternal, loadValue(setterCode.NewCode()));
            }

            setterCode.Load(Crumb.GetParameter(0)).IsNull().Then(x =>
            {
                // Just clear if its clearable
                if (propertyType.Implements(__IList.Type.Fullname))
                {
                    loadValue(x).Callvirt(iList.Clear).Return();
                }
                // Otherwise if the property is not a value type and nullable
                else if (!propertyType.IsValueType || propertyType.IsNullable || propertyType.IsArray)
                {
                    setValue(x, () => null).Return();
                }
                else // otherwise... throw an exception
                {
                    x.ThrowNew(typeof(NotSupportedException), "Value types does not accept null values.");
                }
            });

            if (propertyType.IsArray)
            {
                setterCode.Load(Crumb.GetParameter(0)).Is(typeof(IEnumerable))
                .Then(x => setValue(x, () => Crumb.GetParameter(0)).Return())
                .ThrowNew(typeof(NotSupportedException), "Value does not inherits from IEnumerable");
            }
            else if (propertyType.Implements(__IList.Type.Fullname) && propertyType.ParameterlessContructor != null)
            {
                var addRange = propertyType.GetMethod("AddRange", 1, false);
                if (addRange == null)
                {
                    var add   = propertyType.GetMethod("Add", 1);
                    var array = setterCode.CreateVariable(propertyType.ChildType.MakeArray());
                    setterCode.Assign(array).Set(Crumb.GetParameter(0));
                    setterCode.For(array, (x, item) => loadValue(x).Callvirt(add, item));
                    if (!add.ReturnType.IsVoid)
                    {
                        setterCode.Pop();
                    }
                }
                else
                {
                    loadValue(setterCode).Callvirt(addRange, Crumb.GetParameter(0));
                }
            }
            else if (propertyType.IsEnum)
            {
                // Enums requires special threatment
                setterCode.Load(Crumb.GetParameter(0)).Is(typeof(string)).Then(x =>
                {
                    var stringVariable = setterCode.CreateVariable(typeof(string));
                    setterCode.Assign(stringVariable).Set(Crumb.GetParameter(0));
                    setValue(setterCode, () => stringVariable).Return();
                });

                setValue(setterCode, () => Crumb.GetParameter(0));
            }
            else
            {
                setValue(setterCode, () => Crumb.GetParameter(0));
            }

            setterCode.Return().Replace();
        }
        private static void AddPropertySetterInterception(Builder builder, __PropertyInterceptionInfo propertyInterceptionInfo, PropertyBuilderInfo member, Field propertyField, Method actionObjectCtor, Method propertySetter, Dictionary <string, Field> interceptorFields)
        {
            var syncRoot = new __ISyncRoot();
            var legalSetterInterceptors = member.InterceptorInfos.Where(x => x.InterfaceSetter != null).ToArray();

            member.Property.Setter
            .NewCode()
            .Context(x =>
            {
                if (member.HasInitializer)
                {
                    return;
                }

                for (int i = 0; i < legalSetterInterceptors.Length; i++)
                {
                    var item  = legalSetterInterceptors[i];
                    var field = interceptorFields[item.Attribute.Identification];
                    x.Load(field).IsNull().Then(y =>
                    {
                        y.Assign(field).NewObj(item.Attribute);

                        if (item.HasSyncRootInterface)
                        {
                            y.Load(field).As(syncRoot.ToBuilderType.Import()).Call(syncRoot.SyncRoot, member.SyncRoot);
                        }

                        ImplementAssignMethodAttribute(builder, legalSetterInterceptors[i].AssignMethodAttributeInfos, field, y, false);
                    });
                    item.Attribute.Remove();
                }

                x.Load(propertyField).IsNull().Then(y =>
                                                    y.Assign(propertyField)
                                                    .NewObj(propertyInterceptionInfo.Ctor,
                                                            member.Property.Getter,
                                                            member.Property.Setter,
                                                            member.Property.Name,
                                                            member.Property.ReturnType,
                                                            Crumb.This,
                                                            member.Property.ReturnType.IsArray || member.Property.ReturnType.Implements(typeof(IEnumerable)) ? member.Property.ReturnType.ChildType : null,
                                                            propertySetter == null ? null : y.NewCode().NewObj(actionObjectCtor, propertySetter)));
            })
            .Try(x =>
            {
                if (member.Property.BackingField == null)
                {
                    var oldvalue = member.Property.Getter == null ? null : x.CreateVariable(member.Property.ReturnType);

                    if (oldvalue != null)
                    {
                        var getter = member.Property.Getter.Copy();
                        x.Call(getter.IsStatic ? null : Crumb.This, getter).StoreLocal(oldvalue);
                    }

                    for (int i = 0; i < legalSetterInterceptors.Length; i++)
                    {
                        var item  = legalSetterInterceptors[i];
                        var field = interceptorFields[item.Attribute.Identification];
                        x.Load(field).As(legalSetterInterceptors[i].InterfaceSetter.ToBuilderType).Call(item.InterfaceSetter.OnSet, propertyField, oldvalue, Crumb.GetParameter(0));

                        x.IsFalse().Then(y => y.OriginalBodyNewMethod());
                    }
                }
                else
                {
                    for (int i = 0; i < legalSetterInterceptors.Length; i++)
                    {
                        var item  = legalSetterInterceptors[i];
                        var field = interceptorFields[item.Attribute.Identification];
                        x.Load(field).As(legalSetterInterceptors[i].InterfaceSetter.ToBuilderType).Call(item.InterfaceSetter.OnSet, propertyField, member.Property.BackingField, Crumb.GetParameter(0));

                        x.IsFalse().Then(y => y.OriginalBody());
                    }
                }
            })
            .Catch(typeof(Exception), x =>
            {
                for (int i = 0; i < legalSetterInterceptors.Length; i++)
                {
                    var item  = legalSetterInterceptors[i];
                    var field = interceptorFields[item.Attribute.Identification];
                    x.Load(field).As(legalSetterInterceptors[i].InterfaceSetter.ToBuilderType).Call(legalSetterInterceptors[i].InterfaceSetter.OnException, x.Exception);
                }

                x.Rethrow();
            })
            .Finally(x =>
            {
                for (int i = 0; i < legalSetterInterceptors.Length; i++)
                {
                    var item  = legalSetterInterceptors[i];
                    var field = interceptorFields[item.Attribute.Identification];
                    x.Load(field).As(legalSetterInterceptors[i].InterfaceSetter.ToBuilderType).Call(legalSetterInterceptors[i].InterfaceSetter.OnExit);
                }
            })
            .EndTry()
            .Return()
            .Replace();
        }
        private static void CreatePropertySetterDelegate(Builder builder, PropertyBuilderInfo member, Method propertySetter)
        {
            var iList      = new __IList(builder);
            var setterCode = propertySetter.NewCode();

            if (!member.Property.BackingField.FieldType.IsGenericType)
            {
                var extensions = new __Extensions(builder);

                if (member.Property.BackingField.FieldType.ParameterlessContructor != null && member.Property.BackingField.FieldType.ParameterlessContructor.IsPublic)
                {
                    setterCode.Load(member.Property.BackingField).IsNull().Then(y =>
                                                                                y.Assign(member.Property.BackingField).Set(propertySetter.NewCode()
                                                                                                                           .NewObj(member.Property.BackingField.FieldType.ParameterlessContructor)));
                }

                // Only this if the property implements idisposable
                if (member.Property.BackingField.FieldType.Implements(typeof(IDisposable)))
                {
                    setterCode.Call(extensions.TryDisposeInternal, member.Property.BackingField);
                }

                setterCode.Load(Crumb.GetParameter(0)).IsNull().Then(x =>
                {
                    // Just clear if its clearable
                    if (member.Property.BackingField.FieldType.Implements(iList.Type.Fullname))
                    {
                        x.Load(member.Property.BackingField).Callvirt(iList.Clear).Return();
                    }
                    // Otherwise if the property is not a value type and nullable
                    else if (!member.Property.BackingField.FieldType.IsValueType || member.Property.BackingField.FieldType.IsNullable || member.Property.BackingField.FieldType.IsArray)
                    {
                        x.Assign(member.Property.BackingField).Set(null).Return();
                    }
                    else // otherwise... throw an exception
                    {
                        x.ThrowNew(typeof(NotSupportedException), "Value types does not accept null values.");
                    }
                });

                if (member.Property.BackingField.FieldType.IsArray)
                {
                    setterCode.Load(Crumb.GetParameter(0)).Is(typeof(IEnumerable))
                    .Then(x => x.Assign(member.Property.BackingField).Set(Crumb.GetParameter(0)).Return())
                    .ThrowNew(typeof(NotSupportedException), "Value does not inherits from IEnumerable");
                }
                else if (member.Property.BackingField.FieldType.Implements(iList.Type.Fullname) && member.Property.BackingField.FieldType.ParameterlessContructor != null)
                {
                    var addRange = member.Property.BackingField.FieldType.GetMethod("AddRange", 1, false);
                    if (addRange == null)
                    {
                        var add   = member.Property.BackingField.FieldType.GetMethod("Add", 1);
                        var array = setterCode.CreateVariable(member.Property.BackingField.FieldType.ChildType.MakeArray());
                        setterCode.Assign(array).Set(Crumb.GetParameter(0));
                        setterCode.For(array, (x, item) => x.Load(member.Property.BackingField).Callvirt(add, item));
                        if (!add.ReturnType.IsVoid)
                        {
                            setterCode.Pop();
                        }
                    }
                    else
                    {
                        setterCode.Load(member.Property.BackingField).Callvirt(addRange, Crumb.GetParameter(0));
                    }
                }
                else if (member.Property.BackingField.FieldType.IsEnum)
                {
                    // Enums requires special threatment
                    setterCode.Load(Crumb.GetParameter(0)).Is(typeof(string)).Then(x =>
                    {
                        var stringVariable = setterCode.CreateVariable(typeof(string));
                        setterCode.Assign(stringVariable).Set(Crumb.GetParameter(0));
                        setterCode.Assign(member.Property.BackingField).Set(stringVariable).Return();
                    });

                    setterCode.Assign(member.Property.BackingField).Set(Crumb.GetParameter(0));
                }
                else
                {
                    setterCode.Assign(member.Property.BackingField).Set(Crumb.GetParameter(0));
                }
            }
            else
            {
                setterCode.Assign(member.Property.BackingField).Set(Crumb.GetParameter(0));
            }

            setterCode.Return().Replace();
        }
        private void CreateComponentCache(Builder builder, BuilderType cauldron)
        {
            var componentAttribute            = __ComponentAttribute.Instance;
            var componentConstructorAttribute = __ComponentConstructorAttribute.Type;
            var factory = __Factory.Instance;

            // Before we start let us find all factoryextensions and add a component attribute to them
            var factoryResolverInterface = __IFactoryResolver.Type;

            this.AddComponentAttribute(builder, builder.FindTypesByInterface(factoryResolverInterface), x => factoryResolverInterface.Fullname);
            // Also the same to all types that inherits from Factory<>
            var factoryGeneric = __Factory_1.Type;

            this.AddComponentAttribute(builder, builder.FindTypesByBaseClass(factoryGeneric), type =>
            {
                var factoryBase = type.BaseClasses.FirstOrDefault(x => x.Fullname.StartsWith("Cauldron.Activator.Factory"));
                if (factoryBase == null)
                {
                    return(type.Fullname);
                }

                return(factoryBase.GetGenericArgument(0).Fullname);
            });

            int counter     = 0;
            var arrayAvatar = builder.GetType("System.Array").New(x => new
            {
                Length = x.GetMethod("get_Length")
            });
            var extensionAvatar = builder.GetType("Cauldron.ExtensionsReflection").New(x => new
            {
                CreateInstance = x.GetMethod("CreateInstance", 2)
            });
            var factoryCacheInterface         = builder.GetType("Cauldron.Activator.IFactoryCache");
            var factoryTypeInfoInterface      = builder.GetType("Cauldron.Activator.IFactoryTypeInfo");
            var createInstanceInterfaceMethod = factoryTypeInfoInterface.GetMethod("CreateInstance", 1);

            // Get all Components
            var components     = builder.FindTypesByAttribute(componentAttribute.ToBuilderType);
            var componentTypes = new List <BuilderType>();

            // Create types with the components properties
            foreach (var component in components)
            {
                this.Log("Hardcoding component factory .ctor: " + component.Type.Fullname);

                var componentType           = builder.CreateType("", TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit, $"<>f__IFactoryTypeInfo_{component.Type.Name}_{counter++}");
                var componentAttributeField = componentType.CreateField(Modifiers.Private, componentAttribute.ToBuilderType, "componentAttribute");
                componentType.AddInterface(factoryTypeInfoInterface);
                componentTypes.Add(componentType);

                // Create ctor
                componentType
                .CreateConstructor()
                .NewCode()
                .Context(x =>
                {
                    x.Load(Crumb.This).Call(builder.GetType(typeof(object)).Import().ParameterlessContructor.Import());
                    x.Assign(componentAttributeField).NewObj(component);
                })
                .Return()
                .Replace();

                // Implement the methods
                componentType.CreateMethod(Modifiers.Public | Modifiers.Overrrides, createInstanceInterfaceMethod.ReturnType, createInstanceInterfaceMethod.Name, createInstanceInterfaceMethod.Parameters)
                .NewCode()
                .Context(x =>
                {
                    var localVariable = x.GetReturnVariable();
                    // Find any method with a componentcontructor attribute
                    var ctors = component.Type.GetMethods(y =>
                    {
                        if (y.Name == ".cctor")
                        {
                            return(true);
                        }

                        if (!y.Resolve().IsPublic || !y.Resolve().IsAssembly)
                        {
                            return(false);
                        }

                        if (y.Name == ".ctor" && y.DeclaringType.FullName.GetHashCode() != component.Type.Fullname.GetHashCode() && y.DeclaringType.FullName != component.Type.Fullname)
                        {
                            return(false);
                        }

                        if (y.Name.StartsWith("set_"))
                        {
                            return(false);
                        }

                        return(true);
                    })
                                .Where(y => y.CustomAttributes.HasAttribute(componentConstructorAttribute))
                                .Concat(
                        component.Type.GetAllProperties().Where(y => y.CustomAttributes.HasAttribute(componentConstructorAttribute))
                        .Select(y =>
                    {
                        y.CustomAttributes.Remove(componentConstructorAttribute);
                        y.CustomAttributes.AddEditorBrowsableAttribute(EditorBrowsableState.Never);

                        return(y.Getter);
                    })
                        )
                                .OrderBy(y => y.Parameters.Length)
                                .ToArray();

                    if (ctors.Length > 0)
                    {
                        bool parameterlessCtorAlreadyHandled = false;

                        for (int index = 0; index < ctors.Length; index++)
                        {
                            this.Log("- " + ctors[index].Fullname);

                            var ctor = ctors[index];
                            // add a EditorBrowsable attribute
                            ctor.CustomAttributes.AddEditorBrowsableAttribute(EditorBrowsableState.Never);
                            var ctorParameters = ctor.Parameters;

                            if (ctorParameters.Length > 0)
                            {
                                // In this case we have to find a parameterless constructor first
                                if (component.Type.ParameterlessContructor != null && !parameterlessCtorAlreadyHandled && component.Type.ParameterlessContructor.IsPublicOrInternal)
                                {
                                    x.Load(Crumb.GetParameter(0)).IsNull().Then(y => y.NewObj(component.Type.ParameterlessContructor).Dup().Call(factory.OnObjectCreation, Crumb.This).Return());
                                    x.Load(Crumb.GetParameter(0)).Call(arrayAvatar.Length).EqualTo(0).Then(y => y.NewObj(component.Type.ParameterlessContructor).Dup().Call(factory.OnObjectCreation, Crumb.This).Return());
                                    parameterlessCtorAlreadyHandled = true;
                                }

                                var code = x.Load(Crumb.GetParameter(0)).Call(arrayAvatar.Length).EqualTo(ctorParameters.Length);

                                for (int i = 0; i < ctorParameters.Length; i++)
                                {
                                    code.And.Load(Crumb.GetParameter(0).UnPacked(i)).Is(ctorParameters[i]);
                                }

                                if (ctor.Name == ".ctor")
                                {
                                    code.Then(y => y.NewObj(ctor, Crumb.GetParameter(0).UnPacked()).Dup().Call(factory.OnObjectCreation, Crumb.This).Return());
                                }
                                else
                                {
                                    code.Then(y => y.Call(ctor, Crumb.GetParameter(0).UnPacked()).Dup().Call(factory.OnObjectCreation, Crumb.This).Return());
                                }
                            }
                            else
                            {
                                if (ctor.Name == ".ctor")
                                {
                                    x.Load(Crumb.GetParameter(0)).IsNull().Then(y => y.NewObj(ctor).Dup().Call(factory.OnObjectCreation, Crumb.This).Return());
                                    x.Load(Crumb.GetParameter(0)).Call(arrayAvatar.Length).EqualTo(0).Then(y => y.NewObj(ctor).Dup().Call(factory.OnObjectCreation, Crumb.This).Return());
                                }
                                else
                                {
                                    x.Load(Crumb.GetParameter(0)).IsNull().Then(y => y.Call(ctor).Dup().Call(factory.OnObjectCreation, Crumb.This).Return());
                                    x.Load(Crumb.GetParameter(0)).Call(arrayAvatar.Length).EqualTo(0).Then(y => y.Call(ctor).Dup().Call(factory.OnObjectCreation, Crumb.This).Return());
                                }

                                parameterlessCtorAlreadyHandled = true;
                            }
                        }
                    }
                    else
                    {
                        // In case we don't have constructor with ComponentConstructor Attribute,
                        // then we should look for a parameterless Ctor
                        if (component.Type.ParameterlessContructor == null)
                        {
                            this.Log(LogTypes.Error, component.Type, $"The component '{component.Type.Fullname}' has no ComponentConstructor attribute or the constructor is not public");
                        }
                        else if (component.Type.ParameterlessContructor.IsPublicOrInternal)
                        {
                            x.Load(Crumb.GetParameter(0)).IsNull().Then(y => y.NewObj(component.Type.ParameterlessContructor).Dup().Call(factory.OnObjectCreation, Crumb.This).Return());
                            x.Load(Crumb.GetParameter(0)).Call(arrayAvatar.Length).EqualTo(0).Then(y => y.NewObj(component.Type.ParameterlessContructor).Dup().Call(factory.OnObjectCreation, Crumb.This).Return());

                            this.Log($"The component '{component.Type.Fullname}' has no ComponentConstructor attribute. A parameterless ctor was found and will be used.");
                        }
                    }
                })
                .Context(x => x.Call(extensionAvatar.CreateInstance, component.Type, Crumb.GetParameter(0)).Dup().Call(factory.OnObjectCreation, Crumb.This).Return())
                .Return()
                .Replace();

                // Implement the properties
                foreach (var property in factoryTypeInfoInterface.Properties)
                {
                    var propertyResult = componentType.CreateProperty(Modifiers.Public | Modifiers.Overrrides, property.ReturnType, property.Name, true);
                    propertyResult.BackingField.Remove();

                    switch (property.Name)
                    {
                    case "ContractName":
                        propertyResult.Getter.NewCode().Call(componentAttributeField, componentAttribute.ContractName).Return().Replace();
                        break;

                    case "CreationPolicy":
                        propertyResult.Getter.NewCode().Call(componentAttributeField, componentAttribute.Policy).Return().Replace();
                        break;

                    case "Priority":
                        propertyResult.Getter.NewCode().Call(componentAttributeField, componentAttribute.Priority).Return().Replace();
                        break;

                    case "Type":
                        propertyResult.Getter.NewCode().Load(component.Type).Return().Replace();
                        break;
                    }
                }

                componentType.CustomAttributes.AddEditorBrowsableAttribute(EditorBrowsableState.Never);
                // Also remove the component attribute
                component.Attribute.Remove();
            }

            this.Log("Adding component IFactoryCache Interface");
            cauldron.AddInterface(factoryCacheInterface);
            var factoryCacheInterfaceAvatar = factoryCacheInterface.New(x => new
            {
                Components = x.GetMethod("GetComponents")
            });
            var ctorCoder = cauldron.ParameterlessContructor.NewCode();

            cauldron.CreateMethod(Modifiers.Public | Modifiers.Overrrides, factoryCacheInterfaceAvatar.Components.ReturnType, factoryCacheInterfaceAvatar.Components.Name)
            .NewCode()
            .Context(x =>
            {
                var resultValue = x.GetReturnVariable();
                x.Newarr(factoryTypeInfoInterface, componentTypes.Count).StoreLocal(resultValue);

                for (int i = 0; i < componentTypes.Count; i++)
                {
                    var field = cauldron.CreateField(Modifiers.Private, factoryTypeInfoInterface, "<FactoryType>f__" + i);
                    x.Load(resultValue);
                    x.StoreElement(factoryTypeInfoInterface, field, i);
                    // x.StoreElement(factoryTypeInfoInterface,
                    // x.NewCode().NewObj(componentTypes[i].ParameterlessContructor), i);
                    ctorCoder.Assign(field).NewObj(componentTypes[i].ParameterlessContructor);
                }
            })
            .Return()
            .Replace();

            ctorCoder.Insert(InsertionPosition.End);
        }
        private void ImplementPropertyChangedEvent(Builder builder)
        {
            var changeAwareInterface = new __IChangeAwareViewModel();
            var eventHandlerGeneric  = new __EventHandler_1();
            var eventHandler         = new __EventHandler();
            var viewModelInterface   = new __IViewModel();

            // Get all viewmodels with implemented change aware interface
            var viewModels = builder.FindTypesByInterface(__IChangeAwareViewModel.Type)
                             .OrderBy(x =>
            {
                if (x.Implements(__IChangeAwareViewModel.Type, false))
                {
                    return(0);
                }

                return(1);
            });

            foreach (var vm in viewModels)
            {
                if (vm.IsInterface)
                {
                    continue;
                }

                var method = vm.GetMethod("<>RaisePropertyChangedEventRaise", false, typeof(string), typeof(object), typeof(object));
                var getIsChangeChangedEvent = __IChangeAwareViewModel.GetIsChangedChanged(vm);
                var getIsChangeEvent        = __IChangeAwareViewModel.GetChanged(vm);

                if (method == null && getIsChangeChangedEvent != null && getIsChangeEvent != null)
                {
                    method = vm.CreateMethod(Modifiers.Protected, "<>RaisePropertyChangedEventRaise", typeof(string), typeof(object), typeof(object));
                    method.NewCode()
                    .Load(Crumb.GetParameter(0)).EqualTo("IsChanged").Then(x =>
                    {
                        x.Load(getIsChangeChangedEvent).IsNotNull().Then(y =>
                                                                         y.Callvirt(getIsChangeChangedEvent, eventHandler.Invoke, Crumb.This, y.NewCode().NewObj(eventHandler.EventArgs.Ctor)))
                        .Call(Crumb.This, viewModelInterface.RaisePropertyChanged, Crumb.GetParameter(0))
                        .Return();
                    })
                    .Load(getIsChangeEvent)
                    .IsNotNull()
                    .Then(x =>
                    {
                        x.Call(Crumb.This, viewModelInterface.RaisePropertyChanged, Crumb.GetParameter(0));
                        x.Load(getIsChangeEvent);
                        x.Callvirt(eventHandlerGeneric.Invoke.MakeGeneric(changeAwareInterface.PropertyIsChangedEventArgs.ToBuilderType),
                                   Crumb.This, x.NewCode().NewObj(changeAwareInterface.PropertyIsChangedEventArgs.Ctor, Crumb.GetParameter(0), Crumb.GetParameter(1), Crumb.GetParameter(2)));
                    })
                    .Return()
                    .Replace();
                    method.CustomAttributes.AddDebuggerBrowsableAttribute(DebuggerBrowsableState.Never);
                }

                if (method == null)
                {
                    continue;
                }

                this.Log($"Implementing RaisePropertyChanged Raise Event in '{vm.Fullname}'");
                var raisePropertyChanged = vm.GetMethod("RaisePropertyChanged", false, typeof(string), typeof(object), typeof(object));

                if (raisePropertyChanged == null)
                {
                    continue;
                }

                if (!raisePropertyChanged.IsAbstract && !raisePropertyChanged.HasMethodBaseCall())
                {
                    raisePropertyChanged
                    .NewCode()
                    .Context(x => x.Call(Crumb.This, method, Crumb.GetParameter(0), Crumb.GetParameter(1), Crumb.GetParameter(2)))
                    .Insert(InsertionPosition.Beginning);
                }

                // Repair IsChanged
                if (!vm.Implements(changeAwareInterface.ToBuilderType, false))
                {
                    continue;
                }

                var isChangedSetter = vm.GetMethod("set_IsChanged", 1, false);
                if (isChangedSetter != null)
                {
                    isChangedSetter.NewCode()
                    .Call(Crumb.This, viewModelInterface.IsLoading)
                    .IsTrue()
                    .Then(x => x.Return())
                    .Insert(InsertionPosition.Beginning);
                }
            }
        }