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(); } }
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); } } }