using System;
using System.Linq.Expressions;
using System.Reflection;
namespace Unity.VisualScripting
{
public abstract class InvokerBase : IOptimizedInvoker
{
protected InvokerBase(MethodInfo methodInfo)
{
if (OptimizedReflection.safeMode)
{
if (methodInfo == null)
{
throw new ArgumentNullException(nameof(methodInfo));
}
}
this.methodInfo = methodInfo;
targetType = methodInfo.DeclaringType;
}
protected readonly Type targetType;
protected readonly MethodInfo methodInfo;
protected void VerifyArgument<TParam>(MethodInfo methodInfo, int argIndex, object arg)
{
if (!typeof(TParam).IsAssignableFrom(arg))
{
throw new ArgumentException($"The provided argument value for '{targetType}.{methodInfo.Name}' does not match the parameter type.\nProvided: {arg?.GetType().ToString() ?? "null"}\nExpected: {typeof(TParam)}", methodInfo.GetParameters()[argIndex].Name);
}
}
public void Compile()
{
if (OptimizedReflection.useJit)
{
CompileExpression();
}
else
{
CreateDelegate();
}
}
protected ParameterExpression[] GetParameterExpressions()
{
var methodParameters = methodInfo.GetParameters();
var parameterTypes = GetParameterTypes();
if (methodParameters.Length != parameterTypes.Length)
{
throw new ArgumentException("Parameter count of method info doesn't match generic argument count.", nameof(methodInfo));
}
for (var i = 0; i < parameterTypes.Length; i++)
{
if (parameterTypes[i] != methodParameters[i].ParameterType)
{
throw new ArgumentException("Parameter type of method info doesn't match generic argument.", nameof(methodInfo));
}
}
var parameterExpressions = new ParameterExpression[parameterTypes.Length];
for (var i = 0; i < parameterTypes.Length; i++)
{
parameterExpressions[i] = Expression.Parameter(parameterTypes[i], "parameter" + i);
}
return parameterExpressions;
}
protected abstract Type[] GetParameterTypes();
public abstract object Invoke(object target, params object[] args);
public virtual object Invoke(object target)
{
throw new TargetParameterCountException();
}
public virtual object Invoke(object target, object arg0)
{
throw new TargetParameterCountException();
}
public virtual object Invoke(object target, object arg0, object arg1)
{
throw new TargetParameterCountException();
}
public virtual object Invoke(object target, object arg0, object arg1, object arg2)
{
throw new TargetParameterCountException();
}
public virtual object Invoke(object target, object arg0, object arg1, object arg2, object arg3)
{
throw new TargetParameterCountException();
}
public virtual object Invoke(object target, object arg0, object arg1, object arg2, object arg3, object arg4)
{
throw new TargetParameterCountException();
}
protected abstract void CompileExpression();
protected abstract void CreateDelegate();
protected abstract void VerifyTarget(object target);
}
}