Init
This commit is contained in:
@@ -0,0 +1,251 @@
|
||||
#if !QC_DISABLED && !QC_DISABLE_BUILTIN_ALL && !QC_DISABLE_BUILTIN_EXTRA
|
||||
using QFSW.QC.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace QFSW.QC.Extras
|
||||
{
|
||||
public static class MegaCommands
|
||||
{
|
||||
private static readonly QuantumSerializer Serializer = new QuantumSerializer();
|
||||
private static readonly QuantumParser Parser = new QuantumParser();
|
||||
|
||||
private static MethodInfo[] ExtractMethods(Type type, string name)
|
||||
{
|
||||
const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.InvokeMethod |
|
||||
BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy;
|
||||
|
||||
MethodInfo[] methods = type.GetMethods(flags).Where(x => x.Name == name).ToArray();
|
||||
if (!methods.Any())
|
||||
{
|
||||
PropertyInfo property = type.GetProperty(name, flags);
|
||||
if (property != null)
|
||||
{
|
||||
methods = new[] {property.GetMethod, property.SetMethod}.Where(x => x != null).ToArray();
|
||||
if (methods.Length > 0)
|
||||
{
|
||||
return methods;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ArgumentException($"No method or property named {name} could be found in class {Serializer.SerializeFormatted(type)}");
|
||||
}
|
||||
|
||||
return methods;
|
||||
}
|
||||
|
||||
private static string GenerateSignature(MethodInfo method)
|
||||
{
|
||||
IEnumerable<string> paramParts = method.GetParameters()
|
||||
.Select(x => (x.Name, x.ParameterType))
|
||||
.Select(x => $"{x.ParameterType.GetDisplayName()} {x.Name}");
|
||||
|
||||
string paramSignature = string.Join(", ", paramParts);
|
||||
return $"{method.Name}({paramSignature})";
|
||||
}
|
||||
|
||||
private static MethodInfo GetIdealOverload(MethodInfo[] methods, bool isStatic, int argc)
|
||||
{
|
||||
methods = methods.Where(x => x.IsStatic == isStatic).ToArray();
|
||||
|
||||
if (methods.Length == 0)
|
||||
{
|
||||
throw new ArgumentException($"No {(isStatic ? "static" : "non-static")} overloads could be found.");
|
||||
}
|
||||
|
||||
if (methods.Length == 1)
|
||||
{
|
||||
return methods[0];
|
||||
}
|
||||
|
||||
methods = methods.Where(x => !x.IsGenericMethod).ToArray();
|
||||
if (methods.Length == 0)
|
||||
{
|
||||
throw new ArgumentException("Generic methods are not supported.");
|
||||
}
|
||||
|
||||
MethodInfo[] argcMatches = methods.Where(x => x.GetParameters().Length == argc).ToArray();
|
||||
if (argcMatches.Length == 1)
|
||||
{
|
||||
return argcMatches[0];
|
||||
}
|
||||
else if (argcMatches.Length == 0)
|
||||
{
|
||||
IEnumerable<string> signatures = methods.Select(GenerateSignature);
|
||||
string combinedSignatures = string.Join("\n", signatures);
|
||||
throw new ArgumentException($"No overloads with {argc} arguments were found. the following overloads are available:\n{combinedSignatures}");
|
||||
}
|
||||
else
|
||||
{
|
||||
IEnumerable<string> signatures = argcMatches.Select(GenerateSignature);
|
||||
string combinedSignatures = string.Join("\n", signatures);
|
||||
throw new ArgumentException($"Multiple overloads with the same argument count were found: please specify the types explicitly.\n{combinedSignatures}");
|
||||
}
|
||||
}
|
||||
|
||||
private static MethodInfo GetIdealOverload(MethodInfo[] methods, bool isStatic, Type[] argTypes)
|
||||
{
|
||||
// Exact matching
|
||||
foreach (MethodInfo method in methods)
|
||||
{
|
||||
if (method.IsStatic == isStatic)
|
||||
{
|
||||
IEnumerable<Type> methodParamTypes = method.GetParameters().Select(x => x.ParameterType);
|
||||
if (methodParamTypes.SequenceEqual(argTypes))
|
||||
{
|
||||
return method;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Polymorphic matching
|
||||
foreach (MethodInfo method in methods)
|
||||
{
|
||||
if (method.IsStatic == isStatic)
|
||||
{
|
||||
ParameterInfo[] methodParams = method.GetParameters();
|
||||
if (methodParams.Length == argTypes.Length)
|
||||
{
|
||||
bool isMatch = methodParams
|
||||
.Select(x => x.ParameterType)
|
||||
.Zip(argTypes, (x, y) => (x, y))
|
||||
.All(pair => pair.x.IsAssignableFrom(pair.y));
|
||||
|
||||
if (isMatch)
|
||||
{
|
||||
return method;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new ArgumentException("No overload with the supplied argument types could be found.");
|
||||
}
|
||||
|
||||
private static object[] CreateArgs(MethodInfo method, string[] rawArgs)
|
||||
{
|
||||
ParameterInfo[] methodParams = method.GetParameters();
|
||||
Type[] argTypes = methodParams.Select(x => x.ParameterType).ToArray();
|
||||
return CreateArgs(method, argTypes, rawArgs);
|
||||
}
|
||||
|
||||
private static object[] CreateArgs(MethodInfo method, Type[] argTypes, string[] rawArgs)
|
||||
{
|
||||
ParameterInfo[] methodParams = method.GetParameters();
|
||||
int defaultArgs = methodParams.Count(x => x.HasDefaultValue);
|
||||
|
||||
if (rawArgs.Length < argTypes.Length - defaultArgs || rawArgs.Length > argTypes.Length)
|
||||
{
|
||||
throw new ArgumentException($"Incorrect number ({rawArgs.Length}) of arguments supplied for {Serializer.SerializeFormatted(method.DeclaringType)}.{method.Name}" +
|
||||
$", expected {argTypes.Length}");
|
||||
}
|
||||
|
||||
object[] parsedArgs = new object[argTypes.Length];
|
||||
for (int i = 0; i < parsedArgs.Length; i++)
|
||||
{
|
||||
if (i < rawArgs.Length)
|
||||
{
|
||||
parsedArgs[i] = Parser.Parse(rawArgs[i], argTypes[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
parsedArgs[i] = methodParams[i].DefaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
return parsedArgs;
|
||||
}
|
||||
|
||||
private static object InvokeAndUnwrapException(this MethodInfo method, object[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
return method.Invoke(null, args);
|
||||
}
|
||||
catch (TargetInvocationException e)
|
||||
{
|
||||
throw e.InnerException;
|
||||
}
|
||||
}
|
||||
|
||||
private static object InvokeAndUnwrapException(this MethodInfo method, IEnumerable<object> targets, object[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
return InvocationTargetFactory.InvokeOnTargets(method, targets, args);
|
||||
}
|
||||
catch (TargetInvocationException e)
|
||||
{
|
||||
throw e.InnerException;
|
||||
}
|
||||
}
|
||||
|
||||
[Command("call-static")]
|
||||
private static object CallStatic(Type classType, string funcName)
|
||||
{
|
||||
return CallStatic(classType, funcName, Array.Empty<string>());
|
||||
}
|
||||
|
||||
[Command("call-static")]
|
||||
private static object CallStatic(Type classType, string funcName, string[] args)
|
||||
{
|
||||
MethodInfo[] methods = ExtractMethods(classType, funcName);
|
||||
MethodInfo method = GetIdealOverload(methods, true, args.Length);
|
||||
|
||||
object[] parsedArgs = CreateArgs(method, args);
|
||||
return method.InvokeAndUnwrapException(parsedArgs);
|
||||
}
|
||||
|
||||
[Command("call-static")]
|
||||
[CommandDescription("Invokes the specified static method or property with the provided arguments. Provide [argTypes] if there are ambiguous overloads")]
|
||||
private static object CallStatic(
|
||||
[CommandParameterDescription("Namespace qualified typename of the class.")] Type classType,
|
||||
[CommandParameterDescription("Name of the method or property.")] string funcName,
|
||||
[CommandParameterDescription("The arguments for the function call.")] string[] args,
|
||||
[CommandParameterDescription("The types of the arguments to resolve ambiguous overloads.")] Type[] argTypes)
|
||||
{
|
||||
MethodInfo[] methods = ExtractMethods(classType, funcName);
|
||||
MethodInfo method = GetIdealOverload(methods, true, argTypes);
|
||||
|
||||
object[] parsedArgs = CreateArgs(method, argTypes, args);
|
||||
return method.InvokeAndUnwrapException(parsedArgs);
|
||||
}
|
||||
|
||||
[Command("call-instance")]
|
||||
private static object CallInstance(Type classType, string funcName, MonoTargetType targetType)
|
||||
{
|
||||
return CallInstance(classType, funcName, targetType, Array.Empty<string>());
|
||||
}
|
||||
|
||||
[Command("call-instance")]
|
||||
private static object CallInstance(Type classType, string funcName, MonoTargetType targetType, string[] args)
|
||||
{
|
||||
MethodInfo[] methods = ExtractMethods(classType, funcName);
|
||||
MethodInfo method = GetIdealOverload(methods, false, args.Length);
|
||||
|
||||
object[] parsedArgs = CreateArgs(method, args);
|
||||
IEnumerable<object> targets = InvocationTargetFactory.FindTargets(classType, targetType);
|
||||
return method.InvokeAndUnwrapException(targets, parsedArgs);
|
||||
}
|
||||
|
||||
[Command("call-instance")]
|
||||
[CommandDescription("Invokes the specified non-static method or property with the provided arguments. Provide [argTypes] if there are ambiguous overloads")]
|
||||
private static object CallInstance(
|
||||
[CommandParameterDescription("Namespace qualified typename of the class.")] Type classType,
|
||||
[CommandParameterDescription("Name of the method or property.")] string funcName,
|
||||
[CommandParameterDescription("The MonoTargetType used to find the target instances.")] MonoTargetType targetType,
|
||||
[CommandParameterDescription("The arguments for the function call.")] string[] args,
|
||||
[CommandParameterDescription("The types of the arguments to resolve ambiguous overloads.")] Type[] argTypes)
|
||||
{
|
||||
MethodInfo[] methods = ExtractMethods(classType, funcName);
|
||||
MethodInfo method = GetIdealOverload(methods, false, argTypes);
|
||||
|
||||
object[] parsedArgs = CreateArgs(method, argTypes, args);
|
||||
IEnumerable<object> targets = InvocationTargetFactory.FindTargets(classType, targetType);
|
||||
return method.InvokeAndUnwrapException(targets, parsedArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user