void InjectRaiseMethodCall(PropertyDefinition property, MethodDefinition raiseMethod) { var setter = property.SetMethod; var body = setter.Body; var firstInstr = body.Instructions.First(); var retInstr = body.Instructions.Last(); var il = body.GetILProcessor(); var info = CheckSetter(body, raiseMethod); switch (info) { case NpcInjectionPropertyInfo.Ok: { var fieldRef = (FieldReference)body.Instructions[2].Operand; var propertyType = setter.Parameters[0].ParameterType; if (propertyType.IsPrimitive) { EmitPrimitiveEqualityCheck(il, firstInstr, fieldRef, retInstr); } else if (propertyType.IsValueType) { EmitValueTypeEqualityCheck(il, firstInstr, fieldRef, retInstr, propertyType); } else { EmitReferenceTypeEqualityCheck(il, firstInstr, fieldRef, retInstr); } goto case NpcInjectionPropertyInfo.NoEqualityCheckInjected; } case NpcInjectionPropertyInfo.NoEqualityCheckInjected: il.InsertBefore(retInstr, Instruction.Create(OpCodes.Ldarg_0)); il.InsertBefore(retInstr, Instruction.Create(OpCodes.Ldstr, property.Name)); il.InsertBefore(retInstr, Instruction.Create(OpCodes.Callvirt, this.module.Import(raiseMethod))); break; } this.callback.NotifyProperty(property.GetQualifiedName(), info); }
/////////////////////////////////////////////////////////////////////// void ProcessProperty(PropertyDefinition property, MethodDefinition raiseMethod, bool isDependencyAware) { if (HasIgnoreNpcAttribute(property)) { this.callback.NotifyProperty(property.GetQualifiedName(), NpcInjectionPropertyInfo.Ignored); return; } if (property.SetMethod != null) { InjectRaiseMethodCall(property, raiseMethod); } if (property.GetMethod != null && isDependencyAware) { InjectDependsUponAttributes(property); } }
void InjectDependsUponAttributes(PropertyDefinition property) { var getter = property.GetMethod; var body = getter.Body; var instructions = body.Instructions; // look for a call to a property getter on this instance ("this.Property"): // Ldarg_0 // Call get_Property var calledProperties = (from instr in instructions.Skip(1) where instr.OpCode == OpCodes.Call || instr.OpCode == OpCodes.Callvirt let methodRef = instr.Operand as MethodReference where methodRef != null && methodRef.Name.StartsWith("get_", StringComparison.Ordinal) let method = methodRef.Resolve() where method.IsGetter && method.IsStatic == false let prev = instr.Previous where prev.OpCode == OpCodes.Ldarg_0 || prev.OpCode == OpCodes.Ldarg && Object.Equals(prev.Operand, 0) select method.Name.Substring(4)) .ToList(); if (calledProperties.Count > 0) { foreach (var calledProperty in calledProperties) { var customAttr = new CustomAttribute( this.module.ImportCtor <DependsUponAttribute>(typeof(string))); customAttr.ConstructorArguments.Add( new CustomAttributeArgument(this.module.TypeSystem.String, calledProperty)); property.CustomAttributes.Add(customAttr); } this.callback.NotifyPropertyDependencies(property.GetQualifiedName(), calledProperties); } }