- add GenericMethodCaller and matching exception

ImproveDataHandling_#25
Simon G 5 years ago
parent 2897acbea0
commit 614ad24b5c
  1. 24
      GBase/Exceptions/GenericMethodNotFoundException.cs
  2. 108
      GBase/Helpers/GenericMethodCaller.cs

@ -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…
Cancel
Save