123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- #if REFLECTION_EMIT_COMPILER
- using System.Reflection;
- using System;
- namespace FastReport.Code.Expressions
- {
- internal static class CustomMethodSearcher
- {
- public static MethodInfo Search(Type onType, string methodName, Type[] requiredArguments)
- {
- // TODO: remove this default logic to work only with new searcher
- MethodInfo methodInfo = onType.GetMethod(methodName, requiredArguments);
- if (methodInfo == null)
- {
- // New searcher
- // TODO: CACHE
- // ['{methodName}_{onType}_{requiredArguments}'] = methodInfo
- MethodInfoExt candidate = MethodInfoExt.Empty;
- // searching compatible methods
- foreach (var method in onType.GetMethods())
- {
- if (method.Name == methodName)
- {
- if (ArgumentsAreEqual(requiredArguments, method, out MethodInfoExt methodInfoExt))
- {
- // comparison with a more suitable method
- if (candidate.CompareTo(methodInfoExt) > 0)
- candidate = methodInfoExt;
- }
- }
- }
- methodInfo = candidate.Method;
- }
- return methodInfo;
- }
- private readonly struct MethodInfoExt : IComparable<MethodInfoExt>
- {
- public readonly MethodInfo Method;
- public readonly int ParamLength;
- public readonly bool HasParamArray;
- public static readonly MethodInfoExt Empty = new MethodInfoExt(null, int.MaxValue, true);
- public MethodInfoExt(MethodInfo method, int paramLength, bool hasParamArray)
- {
- Method = method;
- ParamLength = paramLength;
- HasParamArray = hasParamArray;
- }
- public int CompareTo(MethodInfoExt other)
- {
- const int ItsGreater = -1;
- const int ItsLess = 1;
- if (!HasParamArray && other.HasParamArray)
- return ItsGreater;
- if (HasParamArray && !other.HasParamArray)
- return ItsLess;
- var otherParamLength = other.ParamLength;
- if (!HasParamArray)
- {
- if (ParamLength > otherParamLength)
- return ItsLess;
- if (ParamLength < otherParamLength)
- return ItsGreater;
- }
- else
- {
- if (ParamLength < otherParamLength)
- return ItsLess;
- if (ParamLength > otherParamLength)
- return ItsGreater;
- }
- return 0;
- }
- }
- private static bool ArgumentsAreEqual(Type[] requiredArguments, MethodInfo foundMethod, out MethodInfoExt methodInfoExt)
- {
- ParameterInfo[] parameters = foundMethod.GetParameters();
- methodInfoExt = MethodInfoExt.Empty;
- // if argumentTypes = Empty
- if (requiredArguments.Length == 0)
- {
- if (parameters.Length == 0)
- {
- methodInfoExt = new MethodInfoExt(
- method: foundMethod,
- paramLength: parameters.Length,
- hasParamArray: false);
- return true;
- }
- var parameter = parameters[0];
- return parameter.IsOptional();
- }
- // if parameters = Empty
- if (parameters.Length == 0)
- return false;
- bool hasParamArray = false;
- for (int argIndex = 0, paramIndex = 0; ;)
- {
- var argument = requiredArguments[argIndex];
- var parameter = parameters[paramIndex];
- if (!TypeCompatible(argument, parameter))
- return false;
- argIndex++;
- // parameter isn't 'params []'
- if (!parameter.IsParamArray())
- paramIndex++;
- else
- hasParamArray = true;
- if (argIndex < requiredArguments.Length)
- {
- // if params finished, but arguments aren't
- if (paramIndex >= parameters.Length)
- return false;
- }
- else
- {
- // arguments are over, check the rest of the parameters
- while (parameters.Length - paramIndex > 0)
- {
- parameter = parameters[paramIndex];
- if (parameter.IsParamArray())
- hasParamArray = true;
- if (!parameter.IsOptional())
- return false;
- paramIndex++;
- }
- methodInfoExt = new MethodInfoExt(
- method: foundMethod,
- paramLength: parameters.Length,
- hasParamArray: hasParamArray);
- return true;
- }
- }
- }
- private static bool TypeCompatible(Type type1, ParameterInfo parameter)
- {
- Type paramType = parameter.ParameterType;
- if (TypeCompatible(type1, paramType)) return true;
- // Is it `param T[] args` ?
- if (parameter.IsParamArray())
- {
- var elementType = paramType.GetElementType();
- if (TypeCompatible(type1, elementType)) return true;
- }
- return false;
- }
- private static bool TypeCompatible(Type type1, Type type2)
- {
- if (type1 == type2) return true;
- if (type2.IsAssignableFrom(type1)) return true;
- return false;
- }
- }
- internal static class ParameterInfoHelpers
- {
- internal static bool IsParamArray(this ParameterInfo parameter)
- {
- return parameter.GetCustomAttribute(typeof(ParamArrayAttribute), false) != null;
- }
- internal static bool IsOptional(this ParameterInfo parameter)
- {
- // parameter is 'params []'
- if (parameter.IsParamArray())
- return true;
- // parameter has default value
- if (parameter.HasDefaultValue) // TODO: IsOptional ?
- return true;
- return false;
- }
- }
- }
- #endif
|