internal static object AdjustTypeWithCast(Type operandType, object operandValue, Type toType) { // if no conversion required, we are done if (operandType == toType) { return(operandValue); } if (AdjustValueStandard(operandType, operandValue, toType, out object converted)) { return(converted); } // handle enumerations (done above?) // now it's time for implicit and explicit user defined conversions MethodInfo conversion = RuleValidation.FindExplicitConversion(operandType, toType, out ValidationError error); if (conversion == null) { if (error != null) { throw new RuleEvaluationException(error.ErrorText); } throw new RuleEvaluationException( string.Format(CultureInfo.CurrentCulture, Messages.CastIncompatibleTypes, RuleDecompiler.DecompileType(operandType), RuleDecompiler.DecompileType(toType))); } // now we have a method, need to do the conversion S -> Sx -> Tx -> T Type sx = conversion.GetParameters()[0].ParameterType; Type tx = conversion.ReturnType; if (AdjustValueStandard(operandType, operandValue, sx, out object intermediateResult1)) { // we are happy with the first conversion, so call the user's static method object intermediateResult2 = conversion.Invoke(null, new object[] { intermediateResult1 }); if (AdjustValueStandard(tx, intermediateResult2, toType, out object intermediateResult3)) { return(intermediateResult3); } } throw new RuleEvaluationException( string.Format(CultureInfo.CurrentCulture, Messages.CastIncompatibleTypes, RuleDecompiler.DecompileType(operandType), RuleDecompiler.DecompileType(toType))); }
public RuleExecution(RuleValidation validation, object thisObject) { if (validation == null) { throw new ArgumentNullException("validation"); } if (thisObject == null) { throw new ArgumentNullException("thisObject"); } if (validation.ThisType != thisObject.GetType()) { throw new InvalidOperationException( string.Format(CultureInfo.CurrentCulture, Messages.ValidationMismatch, RuleDecompiler.DecompileType(validation.ThisType), RuleDecompiler.DecompileType(thisObject.GetType()))); } this.validation = validation; //this.activity = thisObject as Activity; this.thisObject = thisObject; this.thisLiteralResult = new RuleLiteralResult(thisObject); }
internal override bool Validate(RuleValidation validation) { bool success = false; string message; RuleExpressionInfo lhsExprInfo = null; if (assignStatement.Left == null) { ValidationError error = new ValidationError(Messages.NullAssignLeft, ErrorNumbers.Error_LeftOperandMissing); error.UserData[RuleUserDataKeys.ErrorObject] = assignStatement; validation.Errors.Add(error); } else { lhsExprInfo = validation.ExpressionInfo(assignStatement.Left); if (lhsExprInfo == null) { lhsExprInfo = RuleExpressionWalker.Validate(validation, assignStatement.Left, true); } } RuleExpressionInfo rhsExprInfo = null; if (assignStatement.Right == null) { ValidationError error = new ValidationError(Messages.NullAssignRight, ErrorNumbers.Error_RightOperandMissing); error.UserData[RuleUserDataKeys.ErrorObject] = assignStatement; validation.Errors.Add(error); } else { rhsExprInfo = RuleExpressionWalker.Validate(validation, assignStatement.Right, false); } if (lhsExprInfo != null && rhsExprInfo != null) { Type expressionType = rhsExprInfo.ExpressionType; Type assignmentType = lhsExprInfo.ExpressionType; if (assignmentType == typeof(NullLiteral)) { // Can't assign to a null literal. ValidationError error = new ValidationError(Messages.NullAssignLeft, ErrorNumbers.Error_LeftOperandInvalidType); error.UserData[RuleUserDataKeys.ErrorObject] = assignStatement; validation.Errors.Add(error); success = false; } else if (assignmentType == expressionType) { // Easy case, they're both the same type. success = true; } else { // The types aren't the same, but it still might be a legal assignment. if (!RuleValidation.TypesAreAssignable(expressionType, assignmentType, assignStatement.Right, out ValidationError error)) { if (error == null) { message = string.Format(CultureInfo.CurrentCulture, Messages.AssignNotAllowed, RuleDecompiler.DecompileType(expressionType), RuleDecompiler.DecompileType(assignmentType)); error = new ValidationError(message, ErrorNumbers.Error_OperandTypesIncompatible); } error.UserData[RuleUserDataKeys.ErrorObject] = assignStatement; validation.Errors.Add(error); } else { success = true; } } } return(success); }
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); }