private MethodInterceptorBuilder ImplementProceed(MethodDefinition method, ExtensionPointAttribute extensionPoint) { LogInfo($"ImplementProceed: {method.ReturnType}"); var builder = new MethodInterceptorBuilder(this, method, extensionPoint); var proceed = new MethodDefinition("Proceed", MethodAttributes.Public, TypeSystem.ObjectReference); proceed.Parameters.Add(new ParameterDefinition(Context.ObjectArrayType)); builder.Proceed = proceed; builder.Build(); proceed.Body.Emit(il => { builder.EmitCallOriginal(il); if (method.ReturnType.CompareTo(TypeSystem.VoidReference)) { // Void methods won't leave anything on the stack, but the proceed method is expected to return a value il.Emit(OpCodes.Ldnull); } else { // If it's a value type, box it il.EmitBoxIfNeeded(method.ReturnType); } il.Emit(OpCodes.Ret); }); return(builder); }
private MethodInterceptorBuilder ImplementProceed(MethodDefinition method, ExtensionPointAttribute extensionPoint) { var builder = new MethodInterceptorBuilder(this, method, extensionPoint); var taskReturnType = Context.TaskTType.MakeGenericInstanceType(TypeSystem.ObjectReference); var proceed = new MethodDefinition("Proceed", MethodAttributes.Public, taskReturnType); proceed.Parameters.Add(new ParameterDefinition(Context.ObjectArrayType)); builder.Proceed = proceed; builder.Build(); proceed.Body.Emit(il => { builder.EmitCallOriginal(il); // Before we return, we need to wrap the original `Task<T>` into a `Task<object>` var unwrappedReturnType = ((GenericInstanceType)method.ReturnType).GenericArguments[0]; var typedInvoke = asyncInvokerWrap.MakeGenericMethod(unwrappedReturnType); il.Emit(OpCodes.Call, typedInvoke); il.Emit(OpCodes.Ret); }); return(builder); }
private void ImplementBody(MethodDefinition method, ILProcessor il, FieldDefinition attributeField, FieldDefinition methodInfoField, MethodInterceptorBuilder builder) { // We want to call the interceptor's setter method: // object InvokeMethod(MethodInfo methodInfo, object instance, object[] parameters, Func<object[], object> invoker) // Get interceptor attribute il.LoadField(attributeField); // Leave MethodInfo on the stack as the first argument il.LoadField(methodInfoField); // Leave the instance on the stack as the second argument EmitInstanceArgument(il, method); // Colllect all the parameters into a single array as the third argument ComposeArgumentsIntoArray(il, method); // Leave the delegate for the proceed implementation on the stack as the fourth argument builder.EmitProceedStruct(il); il.EmitDelegate(builder.ProceedReference, Context.Func2Type, Context.ObjectArrayType, TypeSystem.ObjectReference); // Finally, we emit the call to the interceptor il.Emit(OpCodes.Callvirt, baseInvoke); if (method.ReturnType.CompareTo(TypeSystem.VoidReference)) { il.Emit(OpCodes.Pop); } else { // Now unbox the value if necessary il.EmitUnboxIfNeeded(method.ReturnType, method.DeclaringType); } // Return il.Emit(OpCodes.Ret); }
private void ImplementBody(MethodDefinition method, ILProcessor il, FieldDefinition attributeField, FieldDefinition methodInfoField, MethodInterceptorBuilder builder) { // We want to call the interceptor's setter method: // Task<object> InvokeMethodAsync(MethodInfo methodInfo, object instance, object[] parameters, Func<object[], Task<object>> invoker) // Get interceptor attribute il.LoadField(attributeField); // Leave MethodInfo on the stack as the first argument il.LoadField(methodInfoField); // Leave the instance on the stack as the second argument EmitInstanceArgument(il, method); // Colllect all the parameters into a single array as the third argument ComposeArgumentsIntoArray(il, method); // Leave the delegate for the proceed implementation on the stack as the fourth argument builder.EmitProceedStruct(il); il.EmitDelegate(builder.ProceedReference, Context.Func2Type, Context.ObjectArrayType, Context.TaskTType.MakeGenericInstanceType(TypeSystem.ObjectReference)); // Finally, we emit the call to the interceptor il.Emit(OpCodes.Callvirt, baseInvoke); // Before we return, we need to convert the `Task<object>` to `Task<T>` We use the // AsyncInvoker helper so we don't have to build the state machine from scratch. var unwrappedReturnType = ((GenericInstanceType)method.ReturnType).GenericArguments[0]; var typedInvoke = asyncInvokerUnwrap.MakeGenericMethod(unwrappedReturnType); il.Emit(OpCodes.Call, typedInvoke); // Return il.Emit(OpCodes.Ret); }