commit
af42ee3297
23 changed files with 348 additions and 41 deletions
@ -0,0 +1,24 @@ |
|||||||
|
// Author: Gockner, Simon |
||||||
|
// Created: 2020-11-13 |
||||||
|
// Copyright(c) 2020 SimonG. All Rights Reserved. |
||||||
|
|
||||||
|
using System; |
||||||
|
|
||||||
|
namespace GBase.Exceptions |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// Could not find generic method |
||||||
|
/// </summary> |
||||||
|
internal class GenericMethodNotFoundException : Exception |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// Could not find generic method |
||||||
|
/// </summary> |
||||||
|
/// <param name="functionName">The name of the generic method</param> |
||||||
|
public GenericMethodNotFoundException(string functionName) |
||||||
|
: base($"Could not find function {functionName}") |
||||||
|
{ |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -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 |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// Call a generic method without generic type parameters |
||||||
|
/// </summary> |
||||||
|
/// <param name="caller">The caller of the method</param> |
||||||
|
/// <param name="functionName">The name of the method to call</param> |
||||||
|
/// <param name="bindingFlags">The <see cref="BindingFlags"/> to find the method</param> |
||||||
|
/// <param name="genericParameter">The generic parameter as <see cref="Type"/> parameter</param> |
||||||
|
/// <param name="parameters">The parameters of the method</param> |
||||||
|
/// <returns>The result of invoking the method</returns> |
||||||
|
/// <exception cref="GenericMethodNotFoundException">Could not find the generic method</exception> |
||||||
|
/// <exception cref="Exception">Any <see cref="Exception"/> thrown after invoking the generic method</exception> |
||||||
|
public static object Call(object caller, string functionName, BindingFlags bindingFlags, Type genericParameter, params object[] parameters) => |
||||||
|
GetGenericMethod(caller, functionName, bindingFlags, genericParameter).InvokeGenericMethod(caller, parameters); |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Call a generic method without generic type parameters |
||||||
|
/// </summary> |
||||||
|
/// <param name="caller">The caller of the method</param> |
||||||
|
/// <param name="functionName">The name of the method to call</param> |
||||||
|
/// <param name="bindingFlags">The <see cref="BindingFlags"/> to find the method</param> |
||||||
|
/// <param name="genericParameter">The generic parameter as <see cref="Type"/> parameter</param> |
||||||
|
/// <param name="secondGenericParameter"></param> |
||||||
|
/// <param name="parameters">The parameters of the method</param> |
||||||
|
/// <returns>The result of invoking the method</returns> |
||||||
|
/// <exception cref="GenericMethodNotFoundException">Could not find the generic method</exception> |
||||||
|
/// <exception cref="Exception">Any <see cref="Exception"/> thrown after invoking the generic method</exception> |
||||||
|
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); |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Call a generic method asynchronously without generic type parameters |
||||||
|
/// </summary> |
||||||
|
/// <param name="caller">The caller of the method</param> |
||||||
|
/// <param name="functionName">The name of the method to call</param> |
||||||
|
/// <param name="bindingFlags">The <see cref="BindingFlags"/> to find the method</param> |
||||||
|
/// <param name="genericParameter">The generic parameter as <see cref="Type"/> parameter</param> |
||||||
|
/// <param name="parameters">The parameters of the method</param> |
||||||
|
/// <returns>The result of invoking the method</returns> |
||||||
|
/// <exception cref="GenericMethodNotFoundException">Could not find the generic method</exception> |
||||||
|
/// <exception cref="Exception">Any <see cref="Exception"/> thrown after invoking the generic method</exception> |
||||||
|
public static async Task<object> CallAsync(object caller, string functionName, BindingFlags bindingFlags, Type genericParameter, params object[] parameters) => |
||||||
|
await GetGenericMethod(caller, functionName, bindingFlags, genericParameter).InvokeGenericMethodAsync(caller, parameters); |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Call a generic method asynchronously without generic type parameters |
||||||
|
/// </summary> |
||||||
|
/// <param name="caller">The caller of the method</param> |
||||||
|
/// <param name="functionName">The name of the method to call</param> |
||||||
|
/// <param name="bindingFlags">The <see cref="BindingFlags"/> to find the method</param> |
||||||
|
/// <param name="genericParameter">The generic parameter as <see cref="Type"/> parameter</param> |
||||||
|
/// <param name="secondGenericParameter"></param> |
||||||
|
/// <param name="parameters">The parameters of the method</param> |
||||||
|
/// <returns>The result of invoking the method</returns> |
||||||
|
/// <exception cref="GenericMethodNotFoundException">Could not find the generic method</exception> |
||||||
|
/// <exception cref="Exception">Any <see cref="Exception"/> thrown after invoking the generic method</exception> |
||||||
|
public static async Task<object> 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<object> 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(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue