using QFSW.QC.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace QFSW.QC
{
///
/// Contains the full data about a command and provides an execution point for invoking the command.
///
public class CommandData
{
public readonly string CommandName;
public readonly string CommandDescription;
public readonly string CommandSignature;
public readonly string ParameterSignature;
public readonly string GenericSignature;
public readonly ParameterInfo[] MethodParamData;
public readonly Type[] ParamTypes;
public readonly Type[] GenericParamTypes;
public readonly MethodInfo MethodData;
public readonly MonoTargetType MonoTarget;
private readonly object[] _defaultParameters;
public bool IsGeneric => GenericParamTypes.Length > 0;
public bool IsStatic => MethodData.IsStatic;
public bool HasDescription => !string.IsNullOrWhiteSpace(CommandDescription);
public int ParamCount => ParamTypes.Length - _defaultParameters.Length;
public Type[] MakeGenericArguments(params Type[] genericTypeArguments)
{
if (genericTypeArguments.Length != GenericParamTypes.Length)
{
throw new ArgumentException("Incorrect number of generic substitution types were supplied.");
}
Dictionary substitutionTable = new Dictionary();
for (int i = 0; i < genericTypeArguments.Length; i++)
{
substitutionTable.Add(GenericParamTypes[i].Name, genericTypeArguments[i]);
}
Type[] types = new Type[ParamTypes.Length];
for (int i = 0; i < types.Length; i++)
{
if (ParamTypes[i].ContainsGenericParameters)
{
Type substitution = ConstructGenericType(ParamTypes[i], substitutionTable);
types[i] = substitution;
}
else
{
types[i] = ParamTypes[i];
}
}
return types;
}
private Type ConstructGenericType(Type genericType, Dictionary substitutionTable)
{
if (!genericType.ContainsGenericParameters) { return genericType; }
if (substitutionTable.ContainsKey(genericType.Name)) { return substitutionTable[genericType.Name]; }
if (genericType.IsArray) { return ConstructGenericType(genericType.GetElementType(), substitutionTable).MakeArrayType(); }
if (genericType.IsGenericType)
{
Type baseType = genericType.GetGenericTypeDefinition();
Type[] typeArguments = genericType.GetGenericArguments();
for (int i = 0; i < typeArguments.Length; i++)
{
typeArguments[i] = ConstructGenericType(typeArguments[i], substitutionTable);
}
return baseType.MakeGenericType(typeArguments);
}
throw new ArgumentException($"Could not construct the generic type {genericType}");
}
public object Invoke(object[] paramData, Type[] genericTypeArguments)
{
object[] data = new object[paramData.Length + _defaultParameters.Length];
Array.Copy(paramData, 0, data, 0, paramData.Length);
Array.Copy(_defaultParameters, 0, data, paramData.Length, _defaultParameters.Length);
MethodInfo invokingMethod = GetInvokingMethod(genericTypeArguments);
if (IsStatic)
{
return invokingMethod.Invoke(null, data);
}
IEnumerable