public object Compute(Tolerance?tolerance, params object[] arguments) { this.RequiresNotDisposed(); if (!RecognizedCorrectly) { // Expression was not recognized correctly. return(initialExpression); } var convertedArguments = FormatArgumentsAccordingToParameters(arguments, parametersRegistry?.Dump() ?? Array.Empty <ParameterContext>()); object[]? FormatArgumentsAccordingToParameters( object[] parameterValues, ParameterContext[] parameters) { if (parameterValues.Length != parameters.Length) { return(null); } var finalValues = new object[parameterValues.Length]; var i = 0; object?paramValue = null; while (i < finalValues.Length) { ParameterContext paraContext = parameters[i]; // If there was no continuation, initialize parameter with value. paramValue ??= parameterValues[i]; // Initial filtration switch (paramValue) { case byte convertedParam: paramValue = Convert.ToInt64(convertedParam); continue; case sbyte convertedParam: paramValue = Convert.ToInt64(convertedParam); continue; case short convertedParam: paramValue = Convert.ToInt64(convertedParam); continue; case ushort convertedParam: paramValue = Convert.ToInt64(convertedParam); continue; case int convertedParam: paramValue = Convert.ToInt64(convertedParam); continue; case uint convertedParam: paramValue = Convert.ToInt64(convertedParam); continue; case long convertedParam: paramValue = convertedParam; break; case ulong convertedParam: paramValue = Convert.ToDouble(convertedParam); continue; case float convertedParam: paramValue = Convert.ToDouble(convertedParam); continue; case double convertedParam: paramValue = convertedParam; break; case string convertedParam: paramValue = convertedParam; break; case bool convertedParam: paramValue = convertedParam; break; case byte[] convertedParam: paramValue = convertedParam; break; case Func <byte> convertedParam: paramValue = new Func <long>(() => Convert.ToInt64(convertedParam())); continue; case Func <sbyte> convertedParam: paramValue = new Func <long>(() => Convert.ToInt64(convertedParam())); continue; case Func <short> convertedParam: paramValue = new Func <long>(() => Convert.ToInt64(convertedParam())); continue; case Func <ushort> convertedParam: paramValue = new Func <long>(() => Convert.ToInt64(convertedParam())); continue; case Func <int> convertedParam: paramValue = new Func <long>(() => Convert.ToInt64(convertedParam())); continue; case Func <uint> convertedParam: paramValue = new Func <long>(() => Convert.ToInt64(convertedParam())); continue; case Func <long> convertedParam: paramValue = convertedParam; break; case Func <ulong> convertedParam: paramValue = new Func <double>(() => Convert.ToDouble(convertedParam())); continue; case Func <float> convertedParam: paramValue = new Func <double>(() => Convert.ToDouble(convertedParam())); continue; case Func <double> convertedParam: paramValue = convertedParam; break; case Func <string> convertedParam: paramValue = convertedParam; break; case Func <bool> convertedParam: paramValue = convertedParam; break; case Func <byte[]> convertedParam: paramValue = convertedParam; break; default: // Argument type is not (yet) supported return(null); } // Secondary filtration switch (paramValue) { case long convertedParam: switch (paraContext.ReturnType) { case SupportedValueType.Boolean: paramValue = CreateValue(paraContext, convertedParam != 0); break; case SupportedValueType.ByteArray: paramValue = CreateValue(paraContext, BitConverter.GetBytes(convertedParam)); break; case SupportedValueType.Numeric: switch (paraContext.IsFloat) { case true: paramValue = CreateValue(paraContext, Convert.ToDouble(convertedParam)); break; case false: paramValue = CreateValue(paraContext, convertedParam); break; default: paraContext.DetermineInteger(); continue; } break; case SupportedValueType.String: paramValue = CreateValue( paraContext, StringFormatter.FormatIntoString(convertedParam, stringFormatters)); break; case SupportedValueType.Unknown: paraContext.DetermineType(SupportedValueType.Numeric); continue; } break; case double convertedParam: switch (paraContext.ReturnType) { case SupportedValueType.Boolean: // ReSharper disable once CompareOfFloatsByEqualityOperator - no better idea for now paramValue = CreateValue(paraContext, convertedParam != 0D); break; case SupportedValueType.ByteArray: paramValue = CreateValue(paraContext, BitConverter.GetBytes(convertedParam)); break; case SupportedValueType.Numeric: switch (paraContext.IsFloat) { case true: paramValue = CreateValue(paraContext, convertedParam); break; case false: paramValue = CreateValue(paraContext, Convert.ToInt64(convertedParam)); break; default: paraContext.DetermineFloat(); continue; } break; case SupportedValueType.String: paramValue = CreateValue( paraContext, StringFormatter.FormatIntoString(convertedParam, stringFormatters)); break; case SupportedValueType.Unknown: paraContext.DetermineType(SupportedValueType.Numeric); continue; } break; case bool convertedParam: switch (paraContext.ReturnType) { case SupportedValueType.Boolean: paramValue = CreateValue(paraContext, convertedParam); break; case SupportedValueType.ByteArray: paramValue = CreateValue(paraContext, BitConverter.GetBytes(convertedParam)); break; case SupportedValueType.Numeric: return(null); case SupportedValueType.String: paramValue = CreateValue( paraContext, StringFormatter.FormatIntoString(convertedParam, stringFormatters)); break; case SupportedValueType.Unknown: paraContext.DetermineType(SupportedValueType.Boolean); continue; } break; case string convertedParam: switch (paraContext.ReturnType) { case SupportedValueType.Boolean: paramValue = CreateValue(paraContext, bool.Parse(convertedParam)); break; case SupportedValueType.ByteArray: { if (ParsingFormatter.ParseByteArray(convertedParam, out var byteArrayResult)) { paramValue = CreateValue(paraContext, byteArrayResult); } else { // Cannot parse byte array. return(null); } } break; case SupportedValueType.Numeric: { if (ParsingFormatter.ParseNumeric(convertedParam, out var numericResult)) { switch (numericResult) { case long integerResult: paramValue = CreateValue(paraContext, integerResult); break; case double floatResult: paramValue = CreateValue(paraContext, floatResult); break; default: // Numeric type unknown. return(null); } } else { // Cannot parse numeric type. return(null); } } break; case SupportedValueType.String: paramValue = CreateValue(paraContext, convertedParam); break; case SupportedValueType.Unknown: paraContext.DetermineType(SupportedValueType.String); continue; } break; case byte[] convertedParam: switch (paraContext.ReturnType) { case SupportedValueType.Boolean: paramValue = CreateValue(paraContext, BitConverter.ToBoolean(convertedParam, 0)); break; case SupportedValueType.ByteArray: paramValue = CreateValue(paraContext, convertedParam); break; case SupportedValueType.Numeric: switch (paraContext.IsFloat) { case true: paramValue = CreateValue(paraContext, BitConverter.ToDouble(convertedParam, 0)); break; case false: paramValue = CreateValue(paraContext, BitConverter.ToInt64(convertedParam, 0)); break; default: paraContext.DetermineFloat(); continue; } break; case SupportedValueType.String: paramValue = CreateValue( paraContext, StringFormatter.FormatIntoString(convertedParam, stringFormatters)); break; case SupportedValueType.Unknown: paraContext.DetermineType(SupportedValueType.ByteArray); continue; } break; case Func <long> convertedParam: paraContext.DetermineFunc(); switch (paraContext.ReturnType) { case SupportedValueType.Boolean: paramValue = CreateValueFromFunc(paraContext, () => convertedParam() == 0); break; case SupportedValueType.ByteArray: paramValue = CreateValueFromFunc(paraContext, () => BitConverter.GetBytes(convertedParam())); break; case SupportedValueType.Numeric: switch (paraContext.IsFloat) { case true: paramValue = CreateValueFromFunc(paraContext, () => Convert.ToDouble(convertedParam())); break; case false: paramValue = CreateValueFromFunc(paraContext, convertedParam); break; default: paraContext.DetermineInteger(); continue; } break; case SupportedValueType.String: paramValue = CreateValueFromFunc(paraContext, () => StringFormatter.FormatIntoString(convertedParam(), stringFormatters)); break; case SupportedValueType.Unknown: paraContext.DetermineType(SupportedValueType.Numeric); continue; } break; case Func <double> convertedParam: paraContext.DetermineFunc(); switch (paraContext.ReturnType) { case SupportedValueType.Boolean: // ReSharper disable once CompareOfFloatsByEqualityOperator - no better idea for now paramValue = CreateValueFromFunc(paraContext, () => convertedParam() == 0D); break; case SupportedValueType.ByteArray: paramValue = CreateValueFromFunc(paraContext, () => BitConverter.GetBytes(convertedParam())); break; case SupportedValueType.Numeric: switch (paraContext.IsFloat) { case true: paramValue = CreateValueFromFunc(paraContext, convertedParam); break; case false: paramValue = CreateValueFromFunc(paraContext, () => Convert.ToInt64(convertedParam())); break; default: paraContext.DetermineFloat(); continue; } break; case SupportedValueType.String: paramValue = CreateValueFromFunc(paraContext, () => StringFormatter.FormatIntoString(convertedParam(), stringFormatters)); break; case SupportedValueType.Unknown: paraContext.DetermineType(SupportedValueType.Numeric); continue; } break; case Func <bool> convertedParam: paraContext.DetermineFunc(); switch (paraContext.ReturnType) { case SupportedValueType.Boolean: paramValue = CreateValueFromFunc(paraContext, convertedParam); break; case SupportedValueType.ByteArray: paramValue = CreateValueFromFunc(paraContext, () => BitConverter.GetBytes(convertedParam())); break; case SupportedValueType.Numeric: return(null); case SupportedValueType.String: paramValue = CreateValueFromFunc(paraContext, () => StringFormatter.FormatIntoString(convertedParam(), stringFormatters)); break; case SupportedValueType.Unknown: paraContext.DetermineType(SupportedValueType.Boolean); continue; } break; case Func <string> convertedParam: paraContext.DetermineFunc(); switch (paraContext.ReturnType) { case SupportedValueType.Boolean: paramValue = CreateValueFromFunc(paraContext, () => bool.Parse(convertedParam())); break; case SupportedValueType.ByteArray: paramValue = CreateValueFromFunc(paraContext, () => ParsingFormatter.ParseByteArray(convertedParam(), out var baResult) ? baResult : null); break; case SupportedValueType.Numeric: switch (paraContext.IsFloat) { case true: paramValue = CreateValueFromFunc(paraContext, () => ParsingFormatter.ParseNumeric( convertedParam(), out var numericResult) ? Convert.ToDouble(numericResult, CultureInfo.CurrentCulture) : throw new ArgumentInvalidTypeException(paraContext.Name)); break; case false: paramValue = CreateValueFromFunc(paraContext, () => ParsingFormatter.ParseNumeric( convertedParam(), out var numericResult) ? Convert.ToInt64(numericResult, CultureInfo.CurrentCulture) : throw new ArgumentInvalidTypeException(paraContext.Name)); break; default: paraContext.DetermineFloat(); continue; } break; case SupportedValueType.String: paramValue = CreateValueFromFunc(paraContext, convertedParam); break; case SupportedValueType.Unknown: paraContext.DetermineType(SupportedValueType.String); continue; } break; case Func <byte[]> convertedParam: paraContext.DetermineFunc(); switch (paraContext.ReturnType) { case SupportedValueType.Boolean: paramValue = CreateValueFromFunc(paraContext, () => BitConverter.ToBoolean(convertedParam(), 0)); break; case SupportedValueType.ByteArray: paramValue = CreateValueFromFunc(paraContext, convertedParam); break; case SupportedValueType.Numeric: switch (paraContext.IsFloat) { case true: paramValue = CreateValueFromFunc(paraContext, () => BitConverter.ToDouble(convertedParam(), 0)); break; case false: paramValue = CreateValueFromFunc(paraContext, () => BitConverter.ToInt64(convertedParam(), 0)); break; default: paraContext.DetermineFloat(); continue; } break; case SupportedValueType.String: paramValue = CreateValueFromFunc(paraContext, () => StringFormatter.FormatIntoString(convertedParam(), stringFormatters)); break; case SupportedValueType.Unknown: paraContext.DetermineType(SupportedValueType.ByteArray); continue; } break; default: // Argument type is not (yet) supported return(null); } #pragma warning disable HAA0601 // Value type to reference type conversion causing boxing allocation - This is unavoidable now #pragma warning disable HAA0303 // Considering moving this out of the generic method - Not really possible object CreateValue <T>(ParameterContext parameterContext, T value) => parameterContext.FuncParameter ? new Func <T>(() => value) : (object)value; object CreateValueFromFunc <T>( ParameterContext parameterContext, Func <T> value) => parameterContext.FuncParameter ? (object)value : value(); #pragma warning restore HAA0303 // Considering moving this out of the generic method #pragma warning restore HAA0601 // Value type to reference type conversion causing boxing allocation if (paramValue == null) { return(null); } finalValues[i] = paramValue; paramValue = null; i++; } return(finalValues); } if (convertedArguments == null) { // The arguments could not be correctly converted. return(initialExpression); } Delegate?del; if (body == null) { del = null; } else { try { del = Expression.Lambda( tolerance == null ? body.GenerateExpression() : body.GenerateExpression(tolerance), parametersRegistry?.Dump().Select(p => p.ParameterExpression) ?? Array.Empty <ParameterExpression>()) .Compile(); } catch { // Expression is somehow not valid del = null; } } if (del == null) { // Delegate could not be compiled with the given arguments. return(initialExpression); } try { return(del.DynamicInvoke(convertedArguments)); } catch (OutOfMemoryException) { throw; } catch (DivideByZeroException) { throw; } catch { // Dynamic invocation of generated expression failed. return(initialExpression); } }