/// <summary> /// If supplied expression is of Nullable(T) type, invokes its GetValueOrDefault method. /// </summary> /// <param name="expression"></param> /// <returns></returns> public static Expression RemoveNullability(this Expression expression) { return (expression.IsVoid() ? expression : expression.IsNullableType() ? ConstantHelper.TryEvalConst(null, expression.Type.GetField("Value"), expression) : expression); }
private static bool TryAdjustNumericType(ParseTreeNode root, Expression expr, Type targetType, out Expression adjusted) { if (expr.IsNumeric() && Numerics.Contains(targetType)) { var mySize = Marshal.SizeOf(expr.Type); var targetSize = Marshal.SizeOf(targetType); if (mySize < targetSize) { adjusted = ConstantHelper.TryEvalConst(root, expr, ExpressionType.Convert, targetType); return(true); } if (mySize == targetSize) { if (ReferenceEquals(targetType, typeof(Single)) || ReferenceEquals(targetType, typeof(Double))) { adjusted = ConstantHelper.TryEvalConst(root, expr, ExpressionType.Convert, targetType); return(true); } } // attempt overflow-checked autocast between integer constants, // or from integer to real constants (but never from reals to integers) if (!expr.IsRealNumeric() || !targetType.IsInteger()) { // only attempt to auto-convert constants var constExpr = expr as ConstantExpression; if (constExpr != null) { try { adjusted = ConstantHelper.EvalConst(root, constExpr, ExpressionType.ConvertChecked, targetType); return(true); } catch (Exception e) { if (!(e is TargetInvocationException || e is OverflowException)) { // something unexpected happened throw; } // we'll get here if a conversion to target type causes overflow } } } } adjusted = null; return(false); }
/// <summary> /// Attempts to auto-adjust the size of arguments for a binary arithmetic operation. /// Integers grow up to Int64, Double or Decimal, floats grow up to Decimal. /// </summary> /// <param name="leftExpr">Left argument</param> /// <param name="rightExpr">Right argument</param> /// <param name="root">Corresponding parse tree node</param> /// <exception cref="ArgumentNullException"><paramref name="root"/> is null</exception> /// <exception cref="ArgumentNullException"><paramref name="leftExpr"/> is null</exception> /// <exception cref="ArgumentNullException"><paramref name="rightExpr"/> is null</exception> /// <exception cref="CompilationException">Argument types cannot be adjusted, try conversion</exception> public static void AdjustArgumentsForBinaryOperation(ref Expression leftExpr, ref Expression rightExpr, ParseTreeNode root) { if (root == null) { throw new ArgumentNullException("root"); } if (leftExpr == null) { throw new ArgumentNullException("leftExpr"); } if (rightExpr == null) { throw new ArgumentNullException("rightExpr"); } // do we actually have to adjust them? if (ReferenceEquals(leftExpr.Type, rightExpr.Type)) { return; } if (leftExpr.IsNumeric() && rightExpr.IsNumeric()) { var leftSize = Marshal.SizeOf(leftExpr.Type); var rightSize = Marshal.SizeOf(rightExpr.Type); if (leftSize < rightSize) { leftExpr = ConstantHelper.TryEvalConst(root, leftExpr, ExpressionType.Convert, rightExpr.Type); } else if (leftSize > rightSize) { rightExpr = ConstantHelper.TryEvalConst(root, rightExpr, ExpressionType.Convert, leftExpr.Type); } else if (ReferenceEquals(leftExpr.Type, typeof(Single))) { // sizes are equal, so the other guy is probably Int32 or UInt32 rightExpr = ConstantHelper.TryEvalConst(root, rightExpr, ExpressionType.Convert, leftExpr.Type); } else if (ReferenceEquals(rightExpr.Type, typeof(Single))) { // sizes are equal, so the other guy is probably Int32 or UInt32 leftExpr = ConstantHelper.TryEvalConst(root, leftExpr, ExpressionType.Convert, rightExpr.Type); } else if (ReferenceEquals(leftExpr.Type, typeof(Double))) { // sizes are equal, so the other guy is probably Int64 or UInt64 rightExpr = ConstantHelper.TryEvalConst(root, rightExpr, ExpressionType.Convert, leftExpr.Type); } else if (ReferenceEquals(rightExpr.Type, typeof(Double))) { // sizes are equal, so the other guy is probably Int64 or UInt64 leftExpr = ConstantHelper.TryEvalConst(root, leftExpr, ExpressionType.Convert, rightExpr.Type); } } else { throw new CompilationException( String.Format( "Argument types {0} and {1} cannot be auto-adjusted, try conversion", leftExpr.Type.FullName, rightExpr.Type.FullName), root); } }