public EventInvokerMethod AddOnPropertyChangingMethod(TypeDefinition targetType) { var propertyChangingField = FindPropertyChangingField(targetType); if (propertyChangingField == null) { return(null); } if (FoundInterceptor) { if (targetType.HasGenericParameters) { var message = string.Format("Error processing '{0}'. Interception is not supported on generic types. To manually work around this problem add a [DoNotNotify] to the class and then manually implement INotifyPropertyChanging for that class and all child classes. If you would like this feature handled automatically please feel free to submit a pull request.", targetType.Name); throw new WeavingException(message); } var methodDefinition = GetMethodDefinition(targetType, propertyChangingField); return(new EventInvokerMethod { MethodReference = InjectInterceptedMethod(targetType, methodDefinition).GetGeneric(), IsVisibleFromChildren = true, InvokerType = InterceptorType, }); } return(new EventInvokerMethod { MethodReference = InjectMethod(targetType, EventInvokerNames.First(), propertyChangingField).GetGeneric(), IsVisibleFromChildren = true, InvokerType = InterceptorType, }); }
MethodDefinition GetMethodDefinition(TypeDefinition targetType, FieldReference propertyChangedField) { var eventInvokerName = "Inner" + EventInvokerNames.First(); var methodDefinition = targetType.Methods.FirstOrDefault(x => x.Name == eventInvokerName); if (methodDefinition?.Parameters.Count == 1 && methodDefinition.Parameters[0].ParameterType.FullName == "System.String") { return(methodDefinition); } return(InjectMethod(targetType, eventInvokerName, propertyChangedField)); }
MethodDefinition GetMethodDefinition(TypeDefinition targetType) { var eventInvokerName = $"Inner{EventInvokerNames.First()}"; var methodDefinition = targetType.Methods.FirstOrDefault(x => x.Name == eventInvokerName); if (methodDefinition?.Parameters.Count == 1 && methodDefinition.Parameters[0].ParameterType.FullName == "System.String") { return(methodDefinition); } return(InjectMethod(targetType, eventInvokerName)); }
MethodDefinition InjectInterceptedMethod(TypeDefinition targetType, MethodDefinition innerOnPropertyChanging) { var delegateHolderInjector = new DelegateHolderInjector { TargetTypeDefinition = targetType, OnPropertyChangingMethodReference = innerOnPropertyChanging, ModuleWeaver = this }; delegateHolderInjector.InjectDelegateHolder(); var method = new MethodDefinition(EventInvokerNames.First(), GetMethodAttributes(targetType), ModuleDefinition.TypeSystem.Void); var propertyName = new ParameterDefinition("propertyName", ParameterAttributes.None, ModuleDefinition.TypeSystem.String); method.Parameters.Add(propertyName); if (InterceptorType == InvokerTypes.Before) { var before = new ParameterDefinition("before", ParameterAttributes.None, ModuleDefinition.TypeSystem.Object); method.Parameters.Add(before); } var action = new VariableDefinition("firePropertyChanging", ActionTypeReference); method.Body.Variables.Add(action); var variableDefinition = new VariableDefinition("delegateHolder", delegateHolderInjector.TypeDefinition); method.Body.Variables.Add(variableDefinition); var instructions = method.Body.Instructions; var last = Instruction.Create(OpCodes.Ret); instructions.Add(Instruction.Create(OpCodes.Newobj, delegateHolderInjector.ConstructorDefinition)); instructions.Add(Instruction.Create(OpCodes.Stloc_1)); instructions.Add(Instruction.Create(OpCodes.Ldloc_1)); instructions.Add(Instruction.Create(OpCodes.Ldarg_1)); instructions.Add(Instruction.Create(OpCodes.Stfld, delegateHolderInjector.PropertyName)); instructions.Add(Instruction.Create(OpCodes.Ldloc_1)); instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); instructions.Add(Instruction.Create(OpCodes.Stfld, delegateHolderInjector.Target)); instructions.Add(Instruction.Create(OpCodes.Ldloc_1)); instructions.Add(Instruction.Create(OpCodes.Ldftn, delegateHolderInjector.MethodDefinition)); instructions.Add(Instruction.Create(OpCodes.Newobj, ActionConstructorReference)); instructions.Add(Instruction.Create(OpCodes.Stloc_0)); instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); instructions.Add(Instruction.Create(OpCodes.Ldloc_0)); instructions.Add(Instruction.Create(OpCodes.Ldloc_1)); instructions.Add(Instruction.Create(OpCodes.Ldfld, delegateHolderInjector.PropertyName)); if (InterceptorType == InvokerTypes.Before) { instructions.Add(Instruction.Create(OpCodes.Ldarg_2)); instructions.Add(Instruction.Create(OpCodes.Call, InterceptMethod)); } else { instructions.Add(Instruction.Create(OpCodes.Call, InterceptMethod)); } instructions.Add(last); method.Body.InitLocals = true; targetType.Methods.Add(method); return(method); }