/// <summary> /// Attempts to coerce the operand types on a binary operation for some special type and value cases as treated by JsonValue: /// "true" and "false" can be converted to boolean. /// Guid, DateTime and other types can be converted to string. /// </summary> /// <param name="thisOperand">The first operand.</param> /// <param name="otherOperand">The second operand</param> /// <param name="coercedType">On success, this parameter contains the coerced type.</param> /// <returns>true if the coercion is performed, false otherwise.</returns> private static bool TryCoerceSpecialTypes(DynamicMetaObject thisOperand, DynamicMetaObject otherOperand, out Type coercedType) { JsonValue thisValue = thisOperand.Value as JsonValue; JsonValue otherValue = otherOperand.Value as JsonValue; if (thisValue is JsonPrimitive) { Type thisType = thisValue.Read().GetType(); if (thisType != otherOperand.LimitType) { if (otherOperand.LimitType == typeof(string) || (thisType == typeof(string) && otherValue == null)) { object value; if (thisValue.TryReadAs(otherOperand.LimitType, out value)) { coercedType = otherOperand.LimitType; return(true); } } } } coercedType = default(Type); return(false); }
/// <summary> /// Updates the <see cref="Expression"/> tree for the operands of the specified operation. /// </summary> /// <param name="operation">The operation to evalutes.</param> /// <param name="thisOperand">The first operand.</param> /// <param name="otherOperand">The second operand.</param> /// <param name="thisExpression">The <see cref="Expression"/> for the first operand.</param> /// <param name="otherExpression">The <see cref="Expression"/> for the second operand.</param> private static void GetBinaryOperandExpressions(ExpressionType operation, DynamicMetaObject thisOperand, DynamicMetaObject otherOperand, ref Expression thisExpression, ref Expression otherExpression) { JsonValue thisValue = thisOperand.Value as JsonValue; JsonValue otherValue = otherOperand.Value as JsonValue; Type thisType = thisValue.Read().GetType(); Type otherType = otherValue != null?otherValue.Read().GetType() : otherOperand.Value.GetType(); Type coercedType; if (JsonValueDynamicMetaObject.TryCoerceType(operation, thisType, otherType, out coercedType)) { thisType = otherType = coercedType; } else if (JsonValueDynamicMetaObject.TryCoerceSpecialTypes(thisOperand, otherOperand, out coercedType)) { thisType = otherType = coercedType; } thisExpression = Expression.Convert(thisExpression, thisOperand.LimitType); thisExpression = Expression.Convert(Expression.Call(thisExpression, ReadAsMethodInfo, new Expression[] { Expression.Constant(thisType) }), thisType); otherExpression = Expression.Convert(otherExpression, otherOperand.LimitType); if (otherValue != null) { otherExpression = Expression.Convert(Expression.Call(otherExpression, ReadAsMethodInfo, new Expression[] { Expression.Constant(otherType) }), otherType); } else if (otherOperand.LimitType != otherType) { otherExpression = Expression.Convert(otherExpression, otherType); } }
/// <summary> /// Gets the return type for unary operations. /// </summary> /// <param name="binder">The unary operation binder.</param> /// <returns>The type representing the operation return type.</returns> private Type GetUnaryOperationReturnType(UnaryOperationBinder binder) { JsonValue thisValue = this.Value as JsonValue; Type returnType = binder.ReturnType == typeof(object) ? thisValue.Read().GetType() : binder.ReturnType; //// The DLR sets the binder.ReturnType for the unary 'Not' operation as 'object' as opposed to 'bool', //// we need to detect this case and fix up the type to enable boolean conversions from strings. if (returnType == typeof(string) && binder.Operation == ExpressionType.Not) { bool boolVal; if (thisValue.TryReadAs <bool>(out boolVal)) { returnType = typeof(bool); } } return(returnType); }