protected virtual async ValueTask <TAdapter> InvokeTargetGenericValueTaskAsync <TAdapter>(MethodInfo adapterMethod, AdapterInvocationInformation adapterInvocationInformation, object?[] targetArguments) { dynamic task; // ValueTasks are invariant and casting them is limited. Since await is forced to ValueTask<TDestination> by compiler, // dynamic cast must be used to box the invocation result try { task = (dynamic)adapterInvocationInformation.TargetMethod.Invoke(Target, targetArguments); } catch (TargetInvocationException ex) { ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); // Should not be reached throw ex; } object?targetMethodReturnValue = await task.ConfigureAwait(false); // Get type of T from ValueTask<T> Type adapterMethodReturnTypeWithoutTask = adapterMethod.ReturnType.GenericTypeArguments[0]; Type targetMethodReturnTypeWithoutTask = adapterInvocationInformation.TargetMethod.ReturnType.GenericTypeArguments[0]; TAdapter mappedReturnValue = (TAdapter)AdapterMapper.Map(targetMethodReturnValue, targetMethodReturnTypeWithoutTask, adapterMethodReturnTypeWithoutTask); if (_logger.IsEnabled(LogLevel.Trace)) { _logger.Here(l => l.LogTrace("Target method result: {@0}, adapter method result: {@1}", targetMethodReturnValue, mappedReturnValue)); } return(mappedReturnValue !); }
/// <summary> /// Applies type and method mappings and invokes target method with mapped argument values. Does not call Proceed() because there is nothing to proceed to - this interceptor should always be the last one. /// </summary> /// <param name="invocation">Encapsulates an invocation of a proxied method.</param> public virtual void Intercept(IInvocation invocation) { if (_logger.IsEnteringExitingEnabled()) { _logger.Here(l => l.Entering(invocation.ToLoggerString(simpleType: true) !, invocation.Arguments, invocation.ReturnValue)); } MethodInfo adapterMethod = invocation.Method; AdapterInvocationInformation adapterInvocationInformation = AdapterToTargetMethodDictionary.GetOrAdd(adapterMethod, item => { Type[] adapterMethodTypes = adapterMethod.GetParameters().Select(item => item.ParameterType).ToArray(); Type[] targetMethodTypes = MapSupportedTypes(adapterMethodTypes); MethodInfo targetMethod = MapTargetMethod(TargetType, adapterMethod, targetMethodTypes); AdapterInvocationInformation result = PrepareAdapterInvocationInformation(adapterMethod, targetMethod, adapterMethodTypes, targetMethodTypes); return(result); }); object?[] adapterArguments = invocation.Arguments; object?[] targetArguments = new object?[adapterArguments.Length]; for (int i = 0; i < targetArguments.Length; i++) { targetArguments[i] = AdapterMapper.Map(adapterArguments[i], adapterInvocationInformation.AdapterMethodParameterTypes[i], adapterInvocationInformation.TargetMethodParameterTypes[i]); } object?mappedReturnValue; switch (adapterInvocationInformation.TargetInvocationType) { case InvocationTypes.Sync: mappedReturnValue = InvokeTargetSync(adapterMethod, adapterInvocationInformation, targetArguments, invocation); break; case InvocationTypes.GenericTask: mappedReturnValue = adapterInvocationInformation.InvocationHelper !.Invoke(this, new object[] { adapterMethod, adapterInvocationInformation, targetArguments }); break; case InvocationTypes.Task: mappedReturnValue = InvokeTargetTaskAsync(adapterMethod, adapterInvocationInformation, targetArguments); break; case InvocationTypes.GenericValueTask: mappedReturnValue = adapterInvocationInformation.InvocationHelper !.Invoke(this, new object[] { adapterMethod, adapterInvocationInformation, targetArguments }); break; case InvocationTypes.ValueTask: mappedReturnValue = InvokeTargetValueTaskAsync(adapterMethod, adapterInvocationInformation, targetArguments); break; default: throw new NotImplementedException(); } invocation.ReturnValue = mappedReturnValue; // Return values are logged elsewhere _logger.Here(l => l.Exiting()); }
protected virtual object?InvokeTargetSync(MethodInfo adapterMethod, AdapterInvocationInformation adapterInvocationInformation, object?[] targetArguments, IInvocation invocation) { object?returnValue; try { returnValue = adapterInvocationInformation.TargetMethod.Invoke(Target, targetArguments); } catch (TargetInvocationException ex) { ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); // Should not be reached throw ex; } object?mappedReturnValue = AdapterMapper.Map(returnValue, adapterInvocationInformation.TargetMethod.ReturnType, adapterMethod.ReturnType); if (_logger.IsEnabled(LogLevel.Trace)) { _logger.Here(l => l.LogTrace("Target method result: {@0}, adapter method result: {@1}", returnValue, mappedReturnValue)); } for (int i = 0; i < adapterInvocationInformation.AdapterMethodParameterTypes.Length; i++) { if (adapterInvocationInformation.AdapterMethodParameterTypes[i].IsByRef) { invocation.Arguments[i] = AdapterMapper.Map(targetArguments[i], adapterInvocationInformation.TargetMethodParameterTypes[i], adapterInvocationInformation.AdapterMethodParameterTypes[i]); if (_logger.IsEnabled(LogLevel.Trace)) { _logger.Here(l => l.LogTrace($"Updated adapter method argument. Target method argument[{i}]: {{@0}}, adapter method argument[{i}]: {{@1}}", targetArguments[i], invocation.Arguments[i])); } } } return(mappedReturnValue); }