public Lock(MethodBody body, FieldReference field) { this.m_Body = body; this.m_Field = field; if (field.Resolve().IsStatic) { body.Emit(OpCodes.Ldsfld, field); body.Emit(OpCodes.Call, Lock.m_Enter); } else { body.Emit(OpCodes.Ldarg_0); body.Emit(OpCodes.Ldsfld, field); body.Emit(OpCodes.Call, Lock.m_Enter); } }
protected virtual void ProxyMethod(MethodBody body, MethodReference proceedTargetMethod) { // Initialize method info in static constructor var methodInfoFieldDefinition = new FieldDefinition(Name + "$Info", FieldAttributes.Private | FieldAttributes.Static, ClassWeaver.Context.MethodInfoType); ClassWeaver.ProxyType.Fields.Add(methodInfoFieldDefinition); FieldReference methodInfoField = methodInfoFieldDefinition; FieldReference propertyInfoField = null; PropertyDefinition property = null; if (Method.IsSetter || Method.IsGetter) { property = ClassWeaver.PropertiesByAccessor[Method]; var propertyInfoFieldDeclaration = new FieldDefinition($"{Name}${(Method.IsGetter ? "Get" : "Set")}Info", FieldAttributes.Private | FieldAttributes.Static, ClassWeaver.Context.PropertyInfoType); ClassWeaver.ProxyType.Fields.Add(propertyInfoFieldDeclaration); propertyInfoField = propertyInfoFieldDeclaration; } StaticConstructor.Body.Emit(il => { var methodDeclaringType = Import(Method.DeclaringType); if (ClassWeaver.ProxyType.HasGenericParameters) { var genericProxyType = ClassWeaver.ProxyType.MakeGenericInstanceType(ClassWeaver.ProxyType.GenericParameters.ToArray()); methodInfoField = methodInfoField.Bind(genericProxyType); propertyInfoField = propertyInfoField?.Bind(genericProxyType); methodDeclaringType = ClassWeaver.SourceType.MakeGenericInstanceType(ClassWeaver.ProxyType.GenericParameters.ToArray()); } var methodFinder = ClassWeaver.Context.MethodFinder.MakeGenericInstanceType(methodDeclaringType); // Store MethodInfo into the static field var methodSignature = Method.GenerateSignature(); var findMethod = ClassWeaver.Context.FindMethod.Bind(methodFinder); il.Emit(OpCodes.Ldstr, methodSignature); il.Emit(OpCodes.Call, findMethod); il.Emit(OpCodes.Stsfld, methodInfoField); if (property != null) { // Store PropertyInfo into the static field var findProperty = ClassWeaver.Context.FindProperty.Bind(methodFinder); il.Emit(OpCodes.Ldstr, methodSignature); il.Emit(OpCodes.Call, findProperty); il.Emit(OpCodes.Stsfld, propertyInfoField); } }); // Create proceed method (four different types). The proceed method is what you may call in your invocation handler // in order to invoke the behavior that would have happened without the proxy. The actual behavior depends on the value // of "target". If it's not null, it calls the equivalent method on "target". If it *is* null, then: // // * If it's an interface, it provides a default value // * If it's not an interface, and the method is not abstract, it calls the base implementation of that class. // * If it's abstract, then it provides a default value // // The actual implementation of proceed varies based on whether (where T represents the method's return type): // // * The method's return type is void (Represented by Action) // * The method's return type is Task (Represented by Func<Task>) // * The method's return type is Task<T> (Represented by Func<Task<T>>) // * The method's return type is anything else (Represented by Func<T>) SetUpTypes(); var proceed = new MethodDefinition("Proceed", MethodAttributes.Public | MethodAttributes.Static, ProceedReturnType.ResolveGenericParameter(ClassWeaver.ProxyType)); proceed.Parameters.Add(new ParameterDefinition(ClassWeaver.Context.InvocationType)); proceed.Body = new MethodBody(proceed); proceed.Body.InitLocals = true; ProceedClass.Methods.Add(proceed); MethodReference proceedReference = proceed; TypeReference proceedClass = ProceedClass; if (ProceedClass.HasGenericParameters) { proceedReference = proceed.Bind(proceedClass.MakeGenericInstanceType(ClassWeaver.ProxyType.GenericParameters.Concat(body.Method.GenericParameters).ToArray())); } proceed.Body.Emit(il => { ImplementProceed(Method, body, il, methodInfoField, proceedReference, EmitProceedTarget, proceedTargetMethod, GetProceedCallOpCode()); }); // Implement method body.Emit(il => { ImplementBody(il, methodInfoField, propertyInfoField, proceedReference, proceedTargetMethod); }); }