/// <summary> /// Generates a property call on the parameter. /// </summary> /// <typeparam name="T">The type to call the property from.</typeparam> /// <param name="methodName">Name of the parameter.</param> /// <param name="tolerance">The tolerance for this expression. Can be <c>null</c> (<c>Nothing</c> in Visual Basic).</param> /// <returns>An expression representing a property call.</returns> /// <exception cref="ArgumentException"><paramref name="methodName" /> represents a property that cannot be found.</exception> protected Expression GenerateParameterMethodCall <T>( string methodName, Tolerance?tolerance) { if (string.IsNullOrWhiteSpace(methodName)) { throw new ArgumentException( string.Format( CultureInfo.CurrentCulture, Resources.FunctionCouldNotBeFound, methodName), nameof(methodName)); } MethodInfo mi = typeof(T).GetRuntimeMethod( methodName, Array.Empty <Type>()) ?? throw new ArgumentException( string.Format( CultureInfo.CurrentCulture, Resources.FunctionCouldNotBeFound, methodName), nameof(methodName)); return(tolerance == null ? Expression.Call( Parameter.GenerateExpression(), mi) : Expression.Call( Parameter.GenerateExpression(tolerance), mi)); }
/// <summary> /// Generates a property call on the parameter. /// </summary> /// <typeparam name="T">The type to call the property from.</typeparam> /// <param name="propertyName">Name of the parameter.</param> /// <param name="tolerance">The tolerance for this expression. Can be <c>null</c> (<c>Nothing</c> in Visual Basic).</param> /// <returns>An expression representing a property call.</returns> /// <exception cref="ArgumentException"><paramref name="propertyName" /> represents a property that cannot be found.</exception> protected Expression GenerateParameterPropertyCall <T>( string propertyName, Tolerance?tolerance) { if (string.IsNullOrWhiteSpace(propertyName)) { throw new ArgumentException( string.Format( CultureInfo.CurrentCulture, Resources.FunctionCouldNotBeFound, propertyName), nameof(propertyName)); } PropertyInfo pi = typeof(T).GetRuntimeProperty(propertyName) ?? throw new ArgumentException( string.Format( CultureInfo.CurrentCulture, Resources.FunctionCouldNotBeFound, propertyName), nameof(propertyName)); return(Expression.Property( tolerance == null ? Parameter.GenerateExpression() : Parameter.GenerateExpression(tolerance), pi)); }
private bool DeserializeSecondTouchingPoint(XmlReader reader) { var angleString = reader.GetAttribute("Angle"); var deviationString = reader.GetAttribute("Deviation"); Tolerance?tolerance = null; if (!reader.IsEmptyElement) { while (reader.Read() && reader.NodeType != XmlNodeType.EndElement) { if (reader.Name.Equals("Tolerance")) { tolerance = Tolerance.Deserialize(reader); } } } SecondTouchingPoint = new CircleInProfilePoint { Angle = Property.ObjectToNullableDouble(angleString, CultureInfo.InvariantCulture) ?? 0.0, Deviation = Property.ObjectToNullableDouble(deviationString, CultureInfo.InvariantCulture) ?? 0.0 }; if (tolerance != null) { SecondTouchingPoint.Tolerance = tolerance; } return(true); }
/// <summary> /// Generates a static unary function call. /// </summary> /// <typeparam name="T">The type to call the method from.</typeparam> /// <param name="functionName">Name of the function.</param> /// <param name="tolerance">The tolerance for this expression. Can be <c>null</c> (<c>Nothing</c> in Visual Basic).</param> /// <returns>An expression representing the static function call.</returns> /// <exception cref="ArgumentException"><paramref name="functionName" /> represents a function that cannot be found.</exception> protected Expression GenerateStaticUnaryFunctionCall <T>( string functionName, Tolerance?tolerance) => GenerateStaticUnaryFunctionCall( typeof(T), functionName, tolerance);
/// <summary> /// Computes the expression and returns a result. /// </summary> /// <param name="tolerance">The tolerance.</param> /// <param name="dataFinder">The data finder for the arguments with which to invoke execution of the expression.</param> /// <returns> /// The computed result, or, if the expression is not recognized correctly, the expression as a <see cref="string" />. /// </returns> public object Compute(Tolerance?tolerance, IDataFinder dataFinder) { this.RequiresNotDisposed(); if (!RecognizedCorrectly) { return(initialExpression); } var pars = new List <object>(); _ = Requires.NotNull( dataFinder, nameof(dataFinder)); foreach (ParameterContext p in parametersRegistry?.Dump() ?? Array.Empty <ParameterContext>()) { if (!dataFinder.TryGetData(p.Name, out var data)) { data = null; } pars.Add(data); } return(pars.Any(p => p == null) ? initialExpression : Compute(tolerance, pars.ToArray())); }
/// <summary> /// Generates the expression with tolerance that will be compiled into code. /// </summary> /// <param name="tolerance">The tolerance.</param> /// <returns>The expression.</returns> protected override Expression GenerateExpressionInternal(Tolerance?tolerance) => Expression.Divide( Expression.Convert( Left.GenerateExpression(tolerance), typeof(double)), Expression.Convert( Right.GenerateExpression(tolerance), typeof(double)));
/// <summary> /// Generates the expression with tolerance that will be compiled into code. /// </summary> /// <param name="tolerance">The tolerance.</param> /// <returns>The expression.</returns> protected override Expression GenerateExpressionInternal(Tolerance?tolerance) => Expression.Call( typeof(global::System.Math), nameof(global::System.Math.Pow), null, Expression.Convert( Left.GenerateExpression(tolerance), typeof(double)), Expression.Convert( Right.GenerateExpression(tolerance), typeof(double)));
/// <summary> /// Generates the expression with tolerance that will be compiled into code. /// </summary> /// <param name="tolerance">The tolerance.</param> /// <returns>The expression.</returns> protected override Expression GenerateExpressionInternal(Tolerance?tolerance) { var left = Left.GenerateExpression(tolerance); var right = Right.GenerateExpression(tolerance); EnsureCompatibleNumericExpressions( ref left, ref right); return(Expression.Multiply( left, right)); }
/// <summary> /// Generates a string expression that will be cached before being compiled. /// </summary> /// <param name="tolerance">The tolerance.</param> /// <returns>The generated <see cref="Expression" /> to be cached.</returns> public sealed override Expression GenerateCachedStringExpression(Tolerance?tolerance) { var expression = GenerateExpression(tolerance); if (expression.Type == typeof(string)) { return(expression); } var stringFormatters = SpecialObjectRequestFunction?.Invoke(typeof(IStringFormatter)) as List <IStringFormatter>; return(StringFormatter.CreateStringConversionExpression( expression, stringFormatters)); }
/// <summary> /// Can the given instances be considered equal? /// </summary> public static bool Equals(Tolerance?t1, Tolerance?t2) { if (ReferenceEquals(t1, t2)) { return(true); } if (t1 == null || t2 == null) { return(false); } if (t1.ToleranceType != t2.ToleranceType) { return(false); } switch (t1.ToleranceType) { case ToleranceType.Default: return (t1.Lower.IsCloseTo(t2.Lower) && t1.Upper.IsCloseTo(t2.Upper)); case ToleranceType.Circular: return(t1.CircularToleranceRadius.IsCloseTo(t2.CircularToleranceRadius)); case ToleranceType.Rectangular: return (t1.RectangleToleranceHeight.IsCloseTo(t2.RectangleToleranceHeight) && t1.RectangleToleranceWidth.IsCloseTo(t2.RectangleToleranceWidth)); case ToleranceType.Spatial: return(t1.SpatialTolerance == t2.SpatialTolerance); } return(false); }
/// <summary> /// Gets the expressions of same type from operands. /// </summary> /// <param name="tolerance">The tolerance.</param> /// <returns>The left and right operand expressions.</returns> protected (Expression Left, Expression Right) GetExpressionsOfSameTypeFromOperands(Tolerance?tolerance) { if (Left.ReturnType == SupportedValueType.String || Right.ReturnType == SupportedValueType.String) { return(Left.GenerateStringExpression(tolerance), Right.GenerateStringExpression(tolerance)); } Expression le = Left.GenerateExpression(tolerance); Expression re = Right.GenerateExpression(tolerance); if (le.Type == typeof(double) && re.Type == typeof(long)) { return(Left : le, Right : Expression.Convert( re, typeof(double))); } if (le.Type == typeof(long) && re.Type == typeof(double)) { return(Left : Expression.Convert( le, typeof(double)), Right : re); } return(Left : le, Right : re); }
/// <summary> /// Generates the expression with tolerance that will be compiled into code. /// </summary> /// <param name="tolerance">The tolerance.</param> /// <returns>The expression.</returns> protected override Expression GenerateExpressionInternal(Tolerance?tolerance) => GenerateParameterMethodCall <string>( nameof(string.Trim), tolerance);
/// <summary> /// Generates the expression with tolerance that will be compiled into code. /// </summary> /// <param name="tolerance">The tolerance.</param> /// <returns>The expression.</returns> protected override Expression GenerateExpressionInternal(Tolerance?tolerance) => GenerateStaticBinaryFunctionCall <double, int>( typeof(GlobalSystem.Math), nameof(GlobalSystem.Math.Round), tolerance);
/// <summary> /// Generates an expression with tolerance that will be cached before being compiled. /// </summary> /// <param name="tolerance">The tolerance.</param> /// <returns> /// The generated <see cref="Expression" /> to be cached. /// </returns> /// <remarks> /// <para>This method works by first attempting to simplify this node.</para> /// <para>If the node can be simplified, <see cref="CachedExpressionNodeBase.GenerateExpression()" /> is called on the new node and returned in lieu of this expression.</para> /// <para>If this node cannot be simplified, or its simplification method returns reflexively, <see cref="GenerateExpressionInternal(Tolerance)" /> is called.</para> /// </remarks> public sealed override Expression GenerateCachedExpression(Tolerance?tolerance) { NodeBase simplifiedExpression = Simplify(); return(simplifiedExpression != this ? simplifiedExpression.GenerateExpression(tolerance) : GenerateExpressionInternal(tolerance)); }
/// <summary> /// Generates the expression with tolerance that will be compiled into code. /// </summary> /// <param name="tolerance">The tolerance.</param> /// <returns>The expression.</returns> protected virtual Expression GenerateExpressionInternal(Tolerance?tolerance) => GenerateExpressionInternal();
/// <summary> /// Generates a static unary function call. /// </summary> /// <param name="t">The type to call the method from.</param> /// <param name="functionName">Name of the function.</param> /// <param name="tolerance">The tolerance for this expression. Can be <c>null</c> (<c>Nothing</c> in Visual Basic).</param> /// <returns> /// An expression representing the static function call. /// </returns> /// <exception cref="ArgumentException"><paramref name="functionName" /> represents a function that cannot be found.</exception> protected Expression GenerateStaticUnaryFunctionCall( Type t, string functionName, Tolerance?tolerance) { if (string.IsNullOrWhiteSpace(functionName)) { throw new ArgumentException( string.Format( CultureInfo.CurrentCulture, Resources.FunctionCouldNotBeFound, functionName), nameof(functionName)); } Type parameterType = ParameterTypeFromParameter(Parameter); MethodInfo?mi = t.GetMethodWithExactParameters( functionName, parameterType); if (mi == null) { parameterType = typeof(double); mi = t.GetMethodWithExactParameters( functionName, parameterType); if (mi == null) { parameterType = typeof(long); mi = t.GetMethodWithExactParameters( functionName, parameterType); if (mi == null) { parameterType = typeof(int); mi = t.GetMethodWithExactParameters( functionName, parameterType) ?? throw new ArgumentException( string.Format( CultureInfo.CurrentCulture, Resources.FunctionCouldNotBeFound, functionName), nameof(functionName)); } } } Expression e = tolerance == null ? Parameter.GenerateExpression() : Parameter.GenerateExpression(tolerance); if (e.Type != parameterType) { e = Expression.Convert( e, parameterType); } return(Expression.Call( mi, e)); }
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); } }
/// <summary> /// Generates a static binary function call expression. /// </summary> /// <param name="t">The type to call on.</param> /// <param name="functionName">Name of the function.</param> /// <param name="tolerance">The tolerance, should there be any. This argument can be <c>null</c> (<c>Nothing</c> in Visual Basic).</param> /// <returns> /// Expression. /// </returns> /// <exception cref="ArgumentException">The function name is invalid.</exception> protected Expression GenerateBinaryFunctionCallFirstParameterInstance(Type t, string functionName, Tolerance?tolerance) { if (string.IsNullOrWhiteSpace(functionName)) { throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.FunctionCouldNotBeFound, functionName), nameof(functionName)); } Type firstParameterType = ParameterTypeFromParameter(FirstParameter); Type secondParameterType = ParameterTypeFromParameter(SecondParameter); MethodInfo?mi = t.GetMethodWithExactParameters(functionName, firstParameterType, secondParameterType); if (mi == null) { if ((firstParameterType == typeof(long) && secondParameterType == typeof(double)) || (firstParameterType == typeof(double) && secondParameterType == typeof(long))) { firstParameterType = typeof(double); secondParameterType = typeof(double); mi = t.GetMethodWithExactParameters(functionName, firstParameterType, secondParameterType); if (mi == null) { firstParameterType = typeof(long); secondParameterType = typeof(long); mi = t.GetMethodWithExactParameters(functionName, firstParameterType, secondParameterType); if (mi == null) { firstParameterType = typeof(int); secondParameterType = typeof(int); mi = t.GetMethodWithExactParameters(functionName, firstParameterType, secondParameterType) ?? throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.FunctionCouldNotBeFound, functionName), nameof(functionName)); } } } else { throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.FunctionCouldNotBeFound, functionName), nameof(functionName)); } } Expression e1, e2; if (tolerance == null) { e1 = FirstParameter.GenerateExpression(); e2 = SecondParameter.GenerateExpression(); } else { e1 = FirstParameter.GenerateExpression(tolerance); e2 = SecondParameter.GenerateExpression(tolerance); } if (e1.Type != firstParameterType) { e1 = Expression.Convert(e1, firstParameterType); } if (e2.Type != secondParameterType) { e2 = Expression.Convert(e2, secondParameterType); } return(Expression.Call(e1, mi, e2)); }
/// <summary> /// Generates the expression with tolerance that will be compiled into code. /// </summary> /// <param name="tolerance">The tolerance.</param> /// <returns>The expression.</returns> protected override Expression GenerateExpressionInternal(Tolerance?tolerance) => GenerateStaticUnaryFunctionCall( typeof(GlobalSystem.Math), nameof(GlobalSystem.Math.Log10), tolerance);
/// <summary> /// Generates the expression that will be compiled into code. /// </summary> /// <param name="tolerance">The tolerance.</param> /// <returns> /// The generated <see cref="Expression" />. /// </returns> public sealed override Expression GenerateExpression(Tolerance?tolerance) => generatedExpression ??= GenerateCachedExpression(tolerance);
protected Expression?GenerateNumericalToleranceEquateExpression( Expression leftExpression, Expression rightExpression, Tolerance?tolerance) { if (tolerance?.IntegerToleranceRangeLowerBound != null || tolerance?.IntegerToleranceRangeUpperBound != null) { // Integer tolerance MethodInfo mi = typeof(ToleranceFunctions).GetMethodWithExactParameters( nameof(ToleranceFunctions.EquateRangeTolerant), leftExpression.Type, rightExpression.Type, typeof(long), typeof(long)) !; return(Expression.Call( mi, leftExpression, rightExpression, Expression.Constant( tolerance.IntegerToleranceRangeLowerBound ?? 0L, typeof(long)), Expression.Constant( tolerance.IntegerToleranceRangeUpperBound ?? 0L, typeof(long)))); } if (tolerance?.ToleranceRangeLowerBound != null || tolerance?.ToleranceRangeUpperBound != null) { // Floating-point tolerance MethodInfo mi = typeof(ToleranceFunctions).GetMethodWithExactParameters( nameof(ToleranceFunctions.EquateRangeTolerant), leftExpression.Type, rightExpression.Type, typeof(double), typeof(double)) !; return(Expression.Call( mi, leftExpression, rightExpression, Expression.Constant( tolerance.ToleranceRangeLowerBound ?? 0D, typeof(double)), Expression.Constant( tolerance.ToleranceRangeUpperBound ?? 0D, typeof(double)))); } switch (tolerance?.ProportionalTolerance) { case > 1D: { // Proportional tolerance MethodInfo mi = typeof(ToleranceFunctions).GetMethodWithExactParameters( nameof(ToleranceFunctions.EquateProportionTolerant), leftExpression.Type, rightExpression.Type, typeof(double)) !; return(Expression.Call( mi, leftExpression, rightExpression, Expression.Constant( tolerance.ProportionalTolerance, typeof(double)))); } case < 1D and > 0D: { // Percentage tolerance MethodInfo mi = typeof(ToleranceFunctions).GetMethodWithExactParameters( nameof(ToleranceFunctions.EquatePercentageTolerant), leftExpression.Type, rightExpression.Type, typeof(double)) !; return(Expression.Call( mi, leftExpression, rightExpression, Expression.Constant( tolerance.ProportionalTolerance, typeof(double)))); } default: { return(null); } } }
/// <summary> /// Generates the expression that will be compiled into code as a string expression. /// </summary> /// <param name="tolerance">The tolerance.</param> /// <returns>The generated <see cref="Expression" /> that gives the values as a string.</returns> public virtual Expression GenerateStringExpression(Tolerance?tolerance) => GenerateStringExpression();
/// <summary> /// Generates the expression with tolerance that will be compiled into code. /// </summary> /// <param name="tolerance">The tolerance.</param> /// <returns>The expression.</returns> protected override Expression GenerateExpressionInternal(Tolerance?tolerance) => Expression.Convert( GenerateParameterPropertyCall <string>( nameof(string.Length), tolerance), typeof(long));
/// <summary> /// Generates the expression with tolerance that will be compiled into code. /// </summary> /// <param name="tolerance">The tolerance.</param> /// <returns>The expression.</returns> protected override Expression GenerateExpressionInternal(Tolerance?tolerance) => GenerateStaticBinaryFunctionCall <FunctionNodeRandom>(nameof(GenerateRandom), tolerance);
/// <summary> /// Generates the expression that will be compiled into code as a string expression. /// </summary> /// <param name="tolerance">The tolerance.</param> /// <returns>The generated <see cref="Expression" /> that gives the values as a string.</returns> public override Expression GenerateStringExpression(Tolerance?tolerance) => generatedStringExpression ??= GenerateCachedStringExpression(tolerance);
/// <summary> /// Generates the expression with tolerance that will be compiled into code. /// </summary> /// <param name="tolerance">The tolerance.</param> /// <returns>The expression.</returns> protected override Expression GenerateExpressionInternal(Tolerance?tolerance) { Type firstParameterType = typeof(string); Type secondParameterType = typeof(int); Type thirdParameterType = typeof(int); const string functionName = nameof(string.Substring); MethodInfo mi = typeof(string).GetMethodWithExactParameters( functionName, secondParameterType, thirdParameterType) !; if (mi == null) { throw new InvalidOperationException( string.Format( CultureInfo.CurrentCulture, Resources.FunctionCouldNotBeFound, functionName)); } Expression e1, e2, e3; if (tolerance == null) { e1 = FirstParameter.GenerateExpression(); e2 = SecondParameter.GenerateExpression(); e3 = ThirdParameter.GenerateExpression(); } else { e1 = FirstParameter.GenerateExpression(tolerance); e2 = SecondParameter.GenerateExpression(tolerance); e3 = ThirdParameter.GenerateExpression(tolerance); } if (e1.Type != firstParameterType) { e1 = Expression.Convert( e1, firstParameterType); } if (e2.Type != secondParameterType) { e2 = Expression.Convert( e2, secondParameterType); } if (e3.Type != thirdParameterType) { e3 = Expression.Convert( e3, thirdParameterType); } return(Expression.Call( e1, mi, e2, e3)); }
/// <summary> /// Generates an expression with tolerance that will be cached before being compiled. /// </summary> /// <param name="tolerance">The tolerance.</param> /// <returns> /// The generated <see cref="Expression" /> to be cached. /// </returns> public virtual Expression GenerateCachedExpression(Tolerance?tolerance) => GenerateCachedExpression();
/// <summary> /// Generates a static binary function call with explicit parameter types. /// </summary> /// <typeparam name="TParam1">The type of the first parameter.</typeparam> /// <typeparam name="TParam2">The type of the second parameter.</typeparam> /// <param name="t">The type to call on.</param> /// <param name="functionName">Name of the function.</param> /// <param name="tolerance">The tolerance, should there be any. This argument can be <c>null</c> (<c>Nothing</c> in Visual Basic).</param> /// <returns> /// The generated binary method call expression. /// </returns> /// <exception cref="ArgumentException">The function name is invalid.</exception> protected Expression GenerateStaticBinaryFunctionCall <TParam1, TParam2>(Type t, string functionName, Tolerance?tolerance) { if (string.IsNullOrWhiteSpace(functionName)) { throw new ArgumentException(string.Format(Resources.FunctionCouldNotBeFound, functionName), nameof(functionName)); } Type firstParameterType = ParameterTypeFromParameter(FirstParameter); Type secondParameterType = ParameterTypeFromParameter(SecondParameter); MethodInfo mi = t.GetMethodWithExactParameters(functionName, typeof(TParam1), typeof(TParam2)) ?? throw new FunctionCallNotValidLogicallyException(); Expression e1, e2; if (tolerance == null) { e1 = FirstParameter.GenerateExpression(); e2 = SecondParameter.GenerateExpression(); } else { e1 = FirstParameter.GenerateExpression(tolerance); e2 = SecondParameter.GenerateExpression(tolerance); } if (e1.Type != firstParameterType) { e1 = Expression.Convert(e1, firstParameterType); } if (e2.Type != secondParameterType) { e2 = Expression.Convert(e2, secondParameterType); } if (e1.Type != typeof(TParam1)) { e1 = Expression.Convert(e1, typeof(TParam1)); } if (e2.Type != typeof(TParam2)) { e2 = Expression.Convert(e2, typeof(TParam2)); } return(Expression.Call(mi, e1, e2)); }