/// <summary>
        /// Performs the binding of the dynamic unary operation.
        /// </summary>
        /// <param name="binder">An instance of the <see cref="UnaryOperationBinder"/> that represents the details of the dynamic operation.</param>
        /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
        public override DynamicMetaObject BindUnaryOperation(UnaryOperationBinder binder)
        {
            if (binder == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("binder"));
            }

            Expression operExpression = null;
            JsonValue  jsonValue      = this.Value as JsonValue;

            if (jsonValue is JsonPrimitive)
            {
                OperationSupport supportValue = GetUnaryOperationSupport(binder.Operation, jsonValue);

                if (supportValue == OperationSupport.Supported)
                {
                    Type operationReturnType = this.GetUnaryOperationReturnType(binder);

                    Expression instance       = Expression.Convert(this.Expression, this.LimitType);
                    Expression thisExpression = Expression.Convert(Expression.Call(instance, ReadAsMethodInfo, new Expression[] { Expression.Constant(operationReturnType) }), operationReturnType);

                    operExpression = JsonValueDynamicMetaObject.GetUnaryOperationExpression(binder.Operation, thisExpression);
                }
            }

            if (operExpression == null)
            {
                operExpression = JsonValueDynamicMetaObject.GetOperationErrorExpression(OperationSupport.NotSupportedOnJsonType, binder.Operation, jsonValue, null);
            }

            operExpression = Expression.Convert(operExpression, binder.ReturnType);

            return(new DynamicMetaObject(operExpression, this.DefaultRestrictions));
        }
        /// <summary>
        /// Returns an expression representing a 'throw' instruction based on the specified <see cref="OperationSupport"/> value.
        /// </summary>
        /// <param name="supportValue">The <see cref="OperationSupport"/> value.</param>
        /// <param name="operation">The operation type.</param>
        /// <param name="thisValue">The operation left operand.</param>
        /// <param name="operand">The operation right operand.</param>
        /// <returns>A <see cref="Expression"/> representing a 'throw' instruction.</returns>
        private static Expression GetOperationErrorExpression(OperationSupport supportValue, ExpressionType operation, JsonValue thisValue, object operand)
        {
            string exceptionMessage;
            string operandTypeName = operand != null?operand.GetType().FullName : "<null>";

            switch (supportValue)
            {
            default:
            case OperationSupport.NotSupported:
            case OperationSupport.NotSupportedOnJsonType:
            case OperationSupport.NotSupportedOnValueType:
                exceptionMessage = SG.GetString(SR.OperatorNotDefinedForJsonType, operation, thisValue.JsonType);
                break;

            case OperationSupport.NotSupportedOnOperand:
                exceptionMessage = SG.GetString(SR.OperatorNotAllowedOnOperands, operation, thisValue.GetType().FullName, operandTypeName);
                break;
            }

            return(Expression.Throw(Expression.Constant(new InvalidOperationException(exceptionMessage)), typeof(object)));
        }
        /// <summary>
        /// Performs the binding of the dynamic binary operation.
        /// </summary>
        /// <param name="binder">An instance of the <see cref="BinaryOperationBinder"/> that represents the details of the dynamic operation.</param>
        /// <param name="arg">An instance of the <see cref="DynamicMetaObject"/> representing the right hand side of the binary operation.</param>
        /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
        public override DynamicMetaObject BindBinaryOperation(BinaryOperationBinder binder, DynamicMetaObject arg)
        {
            if (binder == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("binder"));
            }

            if (arg == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("arg"));
            }

            Expression thisExpression  = this.Expression;
            Expression otherExpression = arg.Expression;
            Expression operExpression  = null;

            JsonValue otherValue = arg.Value as JsonValue;
            JsonValue thisValue  = this.Value as JsonValue;

            OperationSupport supportValue = JsonValueDynamicMetaObject.GetBinaryOperationSupport(binder.Operation, thisValue, arg.Value);

            if (supportValue == OperationSupport.Supported)
            {
                if (otherValue != null)
                {
                    if (thisValue is JsonPrimitive && otherValue is JsonPrimitive)
                    {
                        //// operation on primitive types.

                        JsonValueDynamicMetaObject.GetBinaryOperandExpressions(binder.Operation, this, arg, ref thisExpression, ref otherExpression);
                    }
                    else
                    {
                        //// operation on JsonValue types.

                        thisExpression  = Expression.Convert(thisExpression, typeof(JsonValue));
                        otherExpression = Expression.Convert(otherExpression, typeof(JsonValue));
                    }
                }
                else
                {
                    if (arg.Value != null)
                    {
                        //// operation on JSON primitive and CLR primitive

                        JsonValueDynamicMetaObject.GetBinaryOperandExpressions(binder.Operation, this, arg, ref thisExpression, ref otherExpression);
                    }
                    else
                    {
                        //// operation on JsonValue and null.

                        thisExpression = Expression.Convert(thisExpression, typeof(JsonValue));

                        if (thisValue.JsonType == JsonType.Default)
                        {
                            thisExpression = Expression.Constant(null);
                        }
                    }
                }

                operExpression = JsonValueDynamicMetaObject.GetBinaryOperationExpression(binder.Operation, thisExpression, otherExpression);
            }

            if (operExpression == null)
            {
                operExpression = JsonValueDynamicMetaObject.GetOperationErrorExpression(supportValue, binder.Operation, thisValue, arg.Value);
            }

            operExpression = Expression.Convert(operExpression, typeof(object));

            return(new DynamicMetaObject(operExpression, this.DefaultRestrictions));
        }