/// <summary> /// If the specified type is some specific Nullable(T) type, returns its underlying type. /// Otherwise, returns the supplied type. /// </summary> /// <param name="target">The type</param> /// <exception cref="ArgumentNullException"><paramref name="target"/> is null</exception> public static Type GetUnderlyingType(this Type target) { if (target == null) { throw new ArgumentNullException("target"); } return(target.IsNullableType() ? UnboxableNullable.GetUnderlyingType(target) : target); }
/// <summary> /// Attempts to auto-adjust the size of argument to the desired type. /// Integers grow up to Int64, Double or Decimal, floats grow up to Decimal. /// </summary> /// <param name="root">Optional, corresponding parse tree node</param> /// <param name="expr">Expression whose value is to be adjusted, must be of numeric value type</param> /// <param name="targetType">Desired type</param> /// <param name="adjusted">New or same expression</param> /// <exception cref="ArgumentNullException"><paramref name="expr"/> is null</exception> /// <exception cref="ArgumentNullException"><paramref name="targetType"/> is null</exception> public static bool TryAdjustReturnType(ParseTreeNode root, Expression expr, Type targetType, out Expression adjusted) { if (expr == null) { throw new ArgumentNullException("expr"); } if (targetType == null) { throw new ArgumentNullException("targetType"); } // do we actually have to adjust them? if (ReferenceEquals(expr.Type, targetType)) { adjusted = expr; return(true); } if (expr.IsVoid()) { adjusted = GetDefaultExpression(targetType); return(true); } if (targetType.IsNullableType()) { if (expr.IsNullableType()) { var variable = Expression.Variable(expr.Type); var setvar = Expression.Assign(variable, expr); var hasvalue = Expression.Field(variable, "HasValue"); Expression value = Expression.Field(variable, "Value"); Expression adjustedValue; if (TryAdjustReturnType(root, value, UnboxableNullable.GetUnderlyingType(targetType), out adjustedValue)) { adjusted = Expression.Block( targetType, new [] { variable }, setvar, Expression.Condition(hasvalue, MakeNewNullable(targetType, adjustedValue), MakeNewNullable(targetType))); return(true); } } else { Expression adjustedValue; if (TryAdjustReturnType(root, expr, UnboxableNullable.GetUnderlyingType(targetType), out adjustedValue)) { adjusted = MakeNewNullable(targetType, adjustedValue); return(true); } } } else if (expr.IsNullableType()) { var nonnullable = expr.RemoveNullability(); return(TryAdjustReturnType(root, nonnullable, targetType, out adjusted)); } else { return(TryAdjustNumericType(root, expr, targetType, out adjusted)); } adjusted = null; return(false); }