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