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(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); } }