From 614ad24b5c359870716ff1cdafec7d8220b5f454 Mon Sep 17 00:00:00 2001 From: Simon G Date: Fri, 13 Nov 2020 13:17:34 +0100 Subject: [PATCH] - add GenericMethodCaller and matching exception --- .../GenericMethodNotFoundException.cs | 24 ++++ GBase/Helpers/GenericMethodCaller.cs | 108 ++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 GBase/Exceptions/GenericMethodNotFoundException.cs create mode 100644 GBase/Helpers/GenericMethodCaller.cs diff --git a/GBase/Exceptions/GenericMethodNotFoundException.cs b/GBase/Exceptions/GenericMethodNotFoundException.cs new file mode 100644 index 0000000..45f6658 --- /dev/null +++ b/GBase/Exceptions/GenericMethodNotFoundException.cs @@ -0,0 +1,24 @@ +// Author: Gockner, Simon +// Created: 2020-11-13 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System; + +namespace GBase.Exceptions +{ + /// + /// Could not find generic method + /// + internal class GenericMethodNotFoundException : Exception + { + /// + /// Could not find generic method + /// + /// The name of the generic method + public GenericMethodNotFoundException(string functionName) + : base($"Could not find function {functionName}") + { + + } + } +} \ No newline at end of file diff --git a/GBase/Helpers/GenericMethodCaller.cs b/GBase/Helpers/GenericMethodCaller.cs new file mode 100644 index 0000000..9ac3ed5 --- /dev/null +++ b/GBase/Helpers/GenericMethodCaller.cs @@ -0,0 +1,108 @@ +// Author: Gockner, Simon +// Created: 2020-11-13 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System; +using System.Reflection; +using System.Threading.Tasks; +using GBase.Exceptions; + +namespace GBase.Helpers +{ + internal static class GenericMethodCaller + { + /// + /// Call a generic method without generic type parameters + /// + /// The caller of the method + /// The name of the method to call + /// The to find the method + /// The generic parameter as parameter + /// The parameters of the method + /// The result of invoking the method + /// Could not find the generic method + /// Any thrown after invoking the generic method + public static object Call(object caller, string functionName, BindingFlags bindingFlags, Type genericParameter, params object[] parameters) => + GetGenericMethod(caller, functionName, bindingFlags, genericParameter).InvokeGenericMethod(caller, parameters); + + /// + /// Call a generic method without generic type parameters + /// + /// The caller of the method + /// The name of the method to call + /// The to find the method + /// The generic parameter as parameter + /// + /// The parameters of the method + /// The result of invoking the method + /// Could not find the generic method + /// Any thrown after invoking the generic method + public static object Call(object caller, string functionName, BindingFlags bindingFlags, Type genericParameter, Type secondGenericParameter,params object[] parameters) => + GetGenericMethod(caller, functionName, bindingFlags, genericParameter, secondGenericParameter).InvokeGenericMethod(caller, parameters); + + /// + /// Call a generic method asynchronously without generic type parameters + /// + /// The caller of the method + /// The name of the method to call + /// The to find the method + /// The generic parameter as parameter + /// The parameters of the method + /// The result of invoking the method + /// Could not find the generic method + /// Any thrown after invoking the generic method + public static async Task CallAsync(object caller, string functionName, BindingFlags bindingFlags, Type genericParameter, params object[] parameters) => + await GetGenericMethod(caller, functionName, bindingFlags, genericParameter).InvokeGenericMethodAsync(caller, parameters); + + /// + /// Call a generic method asynchronously without generic type parameters + /// + /// The caller of the method + /// The name of the method to call + /// The to find the method + /// The generic parameter as parameter + /// + /// The parameters of the method + /// The result of invoking the method + /// Could not find the generic method + /// Any thrown after invoking the generic method + public static async Task CallAsync(object caller, string functionName, BindingFlags bindingFlags, Type genericParameter, Type secondGenericParameter, params object[] parameters) => + await GetGenericMethod(caller, functionName, bindingFlags, genericParameter, secondGenericParameter).InvokeGenericMethodAsync(caller, parameters); + + private static MethodInfo GetGenericMethod(object caller, string functionName, BindingFlags bindingFlags, params Type[] genericParameters) + { + MethodInfo genericMethod = caller.GetType().GetMethod(functionName, bindingFlags)?.MakeGenericMethod(genericParameters); + + if (genericMethod == null) + throw new GenericMethodNotFoundException(functionName); + + return genericMethod; + } + + private static object InvokeGenericMethod(this MethodInfo genericMethod, object caller, params object[] parameters) + { + try //exceptions thrown by methods called with invoke are wrapped into another exception, the exception thrown by the invoked method can be returned by `Exception.GetBaseException()` + { + return genericMethod.Invoke(caller, parameters); + } + catch (Exception ex) + { + throw ex.GetBaseException(); + } + } + + private static async Task InvokeGenericMethodAsync(this MethodInfo genericMethod, object caller, params object[] parameters) + { + try //exceptions thrown by methods called with invoke are wrapped into another exception, the exception thrown by the invoked method can be returned by `Exception.GetBaseException()` + { + dynamic awaitable = genericMethod.Invoke(caller, parameters); + await awaitable; + return awaitable.GetAwaiter().GetResult(); + } + catch (Exception ex) + { + throw ex.GetBaseException(); + } + } + } +} \ No newline at end of file