private object GetTaskContinuationFromMethodInvocation_Terse(IMethodInvocation methodInvocation, Action <Exception> exceptionHandler) { if (methodInvocation.Method.ReturnType.IsGenericType && methodInvocation.Method.ReturnType.GetGenericTypeDefinition() == typeof(Task <>)) { var faultedTaskContinuationWrapper = new FaultedTaskContinuationWrapper(exceptionHandler); var argumentType = methodInvocation.Method.ReturnType.GetGenericArguments().Single(); return(methodInvocation.Method.ReturnType .GetMethods().Where(m => m.Name == "ContinueWith" && m.ReturnType.IsGenericType && m.GetParameters().Count() == 1) .Single(m => m.GetParameters().Single().ParameterType.GetGenericArguments().First() == methodInvocation.Method.ReturnType) .MakeGenericMethod(argumentType) .Invoke( methodInvocation.ReturnValue, typeof(Func <,>).MakeGenericType(methodInvocation.Method.ReturnType, argumentType).CreateDelegate( faultedTaskContinuationWrapper, faultedTaskContinuationWrapper.GetType().GetMethod("ContinuationFunction").MakeGenericMethod(argumentType)))); } else { var task = (Task)methodInvocation.ReturnValue; return(task.ContinueWith(t => { if (t.IsFaulted) { exceptionHandler(t.Exception); } })); } }
public object GetTaskContinuationFromMethodInvocation(IMethodInvocation methodInvocation, Action <Exception> exceptionHandler) { object taskContinuation = null; var taskType = methodInvocation.ReturnValue.GetType(); /* * act on this method only if it is generic and of type Task<TResult> for some TResult */ if (taskType.IsGenericType && taskType.GetGenericTypeDefinition() == typeof(Task <>)) { /* * the faultedTaskContinuationWrapper will PROVIDE AND EXPOSE the method that will be used as a continuation, * in which will invoke the wrapped exceptionHandler. */ var faultedTaskContinuationWrapper = new FaultedTaskContinuationWrapper(exceptionHandler); //-- the TResult var resultType = taskType.GetGenericArguments().Single(); //-- this gets all the methods named "ContinueWith" that return a generic type (presumably Task<T>) and take a single argument var continueWithMethods = taskType.GetMethods().Where(m => m.Name == "ContinueWith" && m.ReturnType.IsGenericType && m.GetParameters().Count() == 1); //-- this gets the one that takes a Func<Task<T>, R> argument var continueWithMethod = continueWithMethods.Single(m => m.GetParameters().Single().ParameterType.GetGenericArguments().First() == taskType); // construct the actual (closed generic) method based on the above generic definition that will be invoked var closedGenericContinueWithMethod = continueWithMethod.MakeGenericMethod(resultType); var continuationMethod = typeof(Func <,>).MakeGenericType(taskType, resultType).CreateDelegate( faultedTaskContinuationWrapper, faultedTaskContinuationWrapper.GetType().GetMethod("ContinuationMethod").MakeGenericMethod(resultType)); // invoke the "ContinueWith" with method on the original task taskContinuation = closedGenericContinueWithMethod.Invoke(methodInvocation.ReturnValue, continuationMethod); } else { var task = (Task)methodInvocation.ReturnValue; return(task.ContinueWith(t => { if (t.IsFaulted) { exceptionHandler(t.Exception); } })); } return(taskContinuation); }