public static CodeExpression Clone(CodeExpression originalExpression) { if (originalExpression == null) { return(null); } RuleExpressionInternal ruleExpr = GetExpression(originalExpression); CodeExpression newExpr = ruleExpr.Clone(originalExpression); ConditionHelper.CloneUserData(originalExpression, newExpr); return(newExpr); }
private static bool AdjustValueStandard(Type operandType, object operandValue, Type toType, out object converted) { // assume it's the same for now converted = operandValue; // check for null if (operandValue == null) { // are we converting to a value type? if (toType.IsValueType) { // is the conversion to nullable? if (!ConditionHelper.IsNullableValueType(toType)) { // value type and null, so no conversion possible string message = string.Format(CultureInfo.CurrentCulture, Messages.CannotCastNullToValueType, RuleDecompiler.DecompileType(toType)); throw new InvalidCastException(message); } // here we have a Nullable<T> // however, we may need to call the implicit conversion operator if the types are not compatible converted = Activator.CreateInstance(toType); return(RuleValidation.StandardImplicitConversion(operandType, toType, null, out ValidationError error)); } // not a value type, so null is valid return(true); } // check simple cases Type currentType = operandValue.GetType(); if (currentType == toType) { return(true); } // now the fun begins // this should handle most class conversions if (toType.IsAssignableFrom(currentType)) { return(true); } // handle the numerics (both implicit and explicit), along with nullable // note that if the value was null, it's already handled, so value cannot be nullable if ((currentType.IsValueType) && (toType.IsValueType)) { if (currentType.IsEnum) { // strip off the enum representation currentType = Enum.GetUnderlyingType(currentType); ArithmeticLiteral literal = ArithmeticLiteral.MakeLiteral(currentType, operandValue); operandValue = literal.Value; } bool resultNullable = ConditionHelper.IsNullableValueType(toType); Type resultType = (resultNullable) ? Nullable.GetUnderlyingType(toType) : toType; if (resultType.IsEnum) { // Enum.ToObject may throw if currentType is not type SByte, // Int16, Int32, Int64, Byte, UInt16, UInt32, or UInt64. // So we adjust currentValue to the underlying type (which may throw if out of range) Type underlyingType = Enum.GetUnderlyingType(resultType); if (AdjustValueStandard(currentType, operandValue, underlyingType, out object adjusted)) { converted = Enum.ToObject(resultType, adjusted); if (resultNullable) { converted = Activator.CreateInstance(toType, converted); } return(true); } } else if ((resultType.IsPrimitive) || (resultType == typeof(decimal))) { // resultType must be a primitive to continue (not a struct) // (enums and generics handled above) if (currentType == typeof(char)) { char c = (char)operandValue; if (resultType == typeof(float)) { converted = (float)c; } else if (resultType == typeof(double)) { converted = (double)c; } else if (resultType == typeof(decimal)) { converted = (decimal)c; } else { converted = ((IConvertible)c).ToType(resultType, CultureInfo.CurrentCulture); } if (resultNullable) { converted = Activator.CreateInstance(toType, converted); } return(true); } else if (currentType == typeof(float)) { float f = (float)operandValue; if (resultType == typeof(char)) { converted = (char)f; } else { converted = ((IConvertible)f).ToType(resultType, CultureInfo.CurrentCulture); } if (resultNullable) { converted = Activator.CreateInstance(toType, converted); } return(true); } else if (currentType == typeof(double)) { double d = (double)operandValue; if (resultType == typeof(char)) { converted = (char)d; } else { converted = ((IConvertible)d).ToType(resultType, CultureInfo.CurrentCulture); } if (resultNullable) { converted = Activator.CreateInstance(toType, converted); } return(true); } else if (currentType == typeof(decimal)) { decimal d = (decimal)operandValue; if (resultType == typeof(char)) { converted = (char)d; } else { converted = ((IConvertible)d).ToType(resultType, CultureInfo.CurrentCulture); } if (resultNullable) { converted = Activator.CreateInstance(toType, converted); } return(true); } else { if (operandValue is IConvertible convert) { try { converted = convert.ToType(resultType, CultureInfo.CurrentCulture); if (resultNullable) { converted = Activator.CreateInstance(toType, converted); } return(true); } catch (InvalidCastException) { // not IConvertable, so can't do it return(false); } } } } } // no luck with standard conversions, so no conversion done return(false); }