/// <summary>
        /// Converts a query string parameter to the specified type.
        /// </summary>
        /// <param name="parameter">The string form of the parameter and value.</param>
        /// <param name="parameterType">The Type to convert the parameter to.</param>
        /// <returns>The converted parameter.</returns>
        public override object ConvertStringToValue(string parameter, Type parameterType)
        {
            object convertedValue;

            Type underlyingType = Nullable.GetUnderlyingType(parameterType);

            if (String.IsNullOrEmpty(parameter))
            {
                DomainDataServiceQueryStringConverter.CheckSyntaxValid(parameterType.IsClass || underlyingType != null);
                convertedValue = null;
            }
            else
            {
                // We choose to be a little more flexible than with keys and allow surrounding whitespace (which is never significant).
                parameter = parameter.Trim();

                Type targetType = underlyingType ?? parameterType;

                if (DomainDataServiceQueryStringConverter.IsKeyTypeQuoted(targetType))
                {
                    DomainDataServiceQueryStringConverter.CheckSyntaxValid(
                        DomainDataServiceQueryStringConverter.IsKeyValueQuoted(parameter));
                }

                DomainDataServiceQueryStringConverter.CheckSyntaxValid(
                    DomainDataServiceQueryStringConverter.TryKeyStringToPrimitive(
                        parameter,
                        targetType,
                        out convertedValue));
            }

            return(convertedValue);
        }
        /// <summary>Converts a string to a DateTime value.</summary>
        /// <param name="text">String text to convert.</param>
        /// <param name="targetValue">After invocation, converted value.</param>
        /// <returns>true if the value was converted; false otherwise.</returns>
        private static bool TryKeyStringToDateTime(string text, out DateTime targetValue)
        {
            if (!DomainDataServiceQueryStringConverter.TryRemoveLiteralPrefix(TypeUtils.LiteralPrefixDateTime, ref text))
            {
                targetValue = default(DateTime);
                return(false);
            }

            if (!DomainDataServiceQueryStringConverter.TryRemoveQuotes(ref text))
            {
                targetValue = default(DateTime);
                return(false);
            }

            try
            {
                targetValue = XmlConvert.ToDateTime(text, XmlDateTimeSerializationMode.RoundtripKind);
                return(true);
            }
            catch (FormatException)
            {
                targetValue = default(DateTime);
                return(false);
            }
        }
        /// <summary>Converts a string to a GUID value.</summary>
        /// <param name="text">String text to convert.</param>
        /// <param name="targetValue">After invocation, converted value.</param>
        /// <returns>true if the value was converted; false otherwise.</returns>
        private static bool TryKeyStringToGuid(string text, out Guid targetValue)
        {
            if (!DomainDataServiceQueryStringConverter.TryRemoveLiteralPrefix(TypeUtils.LiteralPrefixGuid, ref text))
            {
                targetValue = default(Guid);
                return(false);
            }

            if (!DomainDataServiceQueryStringConverter.TryRemoveQuotes(ref text))
            {
                targetValue = default(Guid);
                return(false);
            }

            try
            {
                targetValue = XmlConvert.ToGuid(text);
                return(true);
            }
            catch (FormatException)
            {
                targetValue = default(Guid);
                return(false);
            }
        }
        /// <summary>Converts a string to a byte[] value.</summary>
        /// <param name="text">String text to convert.</param>
        /// <param name="targetValue">After invocation, converted value.</param>
        /// <returns>true if the value was converted; false otherwise.</returns>
        private static bool TryKeyStringToByteArray(string text, out byte[] targetValue)
        {
            Debug.Assert(text != null, "text != null");

            if (!DomainDataServiceQueryStringConverter.TryRemoveLiteralPrefix(TypeUtils.LiteralPrefixBinary, ref text) &&
                !DomainDataServiceQueryStringConverter.TryRemoveLiteralPrefix(TypeUtils.XmlBinaryPrefix, ref text))
            {
                targetValue = null;
                return(false);
            }

            if (!DomainDataServiceQueryStringConverter.TryRemoveQuotes(ref text))
            {
                targetValue = null;
                return(false);
            }

            if ((text.Length % 2) != 0)
            {
                targetValue = null;
                return(false);
            }

            byte[] result      = new byte[text.Length / 2];
            int    resultIndex = 0;
            int    textIndex   = 0;

            while (resultIndex < result.Length)
            {
                char ch0 = text[textIndex];
                char ch1 = text[textIndex + 1];
                if (!DomainDataServiceQueryStringConverter.IsCharHexDigit(ch0) ||
                    !DomainDataServiceQueryStringConverter.IsCharHexDigit(ch1))
                {
                    targetValue = null;
                    return(false);
                }

                result[resultIndex] = (byte)((byte)(DomainDataServiceQueryStringConverter.HexCharToNibble(ch0) << 4) +
                                             DomainDataServiceQueryStringConverter.HexCharToNibble(ch1));
                textIndex += 2;
                resultIndex++;
            }

            targetValue = result;
            return(true);
        }
        /// <summary>Converts a string to a primitive value.</summary>
        /// <param name="text">String text to convert.</param>
        /// <param name="targetType">Type to convert string to.</param>
        /// <param name="targetValue">After invocation, converted value.</param>
        /// <returns>true if the value was converted; false otherwise.</returns>
        private static bool TryKeyStringToPrimitive(string text, Type targetType, out object targetValue)
        {
            Debug.Assert(text != null, "text != null");
            Debug.Assert(targetType != null, "targetType != null");

            targetType = Nullable.GetUnderlyingType(targetType) ?? targetType;

            byte[] byteArrayValue;
            bool   binaryResult = DomainDataServiceQueryStringConverter.TryKeyStringToByteArray(text, out byteArrayValue);

            if (targetType == typeof(byte[]) || targetType == typeof(System.Data.Linq.Binary))
            {
                // The object cast is required because otherwise the compiler uses the implicit byte[]
                // to Binary conversion and always returns Binary.
                targetValue =
                    (byteArrayValue != null && targetType == typeof(System.Data.Linq.Binary)) ?
                    (object)new System.Data.Linq.Binary(byteArrayValue) : (object)byteArrayValue;
                return(binaryResult);
            }
            else if (binaryResult)
            {
                string keyValue = Encoding.UTF8.GetString(byteArrayValue);
                return(DomainDataServiceQueryStringConverter.TryKeyStringToPrimitive(keyValue, targetType, out targetValue));
            }
            // These have separate handlers for convenience - reuse them.
            else if (targetType == typeof(Guid))
            {
                Guid guidValue;
                bool result = DomainDataServiceQueryStringConverter.TryKeyStringToGuid(text, out guidValue);
                targetValue = guidValue;
                return(result);
            }
            else if (targetType == typeof(DateTime))
            {
                DateTime dateTimeValue;
                bool     result = DomainDataServiceQueryStringConverter.TryKeyStringToDateTime(text, out dateTimeValue);
                targetValue = dateTimeValue;
                return(result);
            }

            bool quoted = DomainDataServiceQueryStringConverter.IsKeyTypeQuoted(targetType);

            if (quoted != DomainDataServiceQueryStringConverter.IsKeyValueQuoted(text))
            {
                targetValue = null;
                return(false);
            }

            if (quoted)
            {
                Debug.Assert(
                    DomainDataServiceQueryStringConverter.IsKeyValueQuoted(text),
                    "IsKeyValueQuoted(text) - otherwise caller didn't check this before");
                text = DomainDataServiceQueryStringConverter.RemoveQuotes(text);
            }

            try
            {
                if (typeof(String) == targetType)
                {
                    targetValue = text;
                }
                else if (typeof(Boolean) == targetType)
                {
                    targetValue = XmlConvert.ToBoolean(text);
                }
                else if (typeof(Byte) == targetType)
                {
                    targetValue = XmlConvert.ToByte(text);
                }
                else if (typeof(SByte) == targetType)
                {
                    targetValue = XmlConvert.ToSByte(text);
                }
                else if (typeof(Int16) == targetType)
                {
                    targetValue = XmlConvert.ToInt16(text);
                }
                else if (typeof(Int32) == targetType)
                {
                    targetValue = XmlConvert.ToInt32(text);
                }
                else if (typeof(Int64) == targetType)
                {
                    if (DomainDataServiceQueryStringConverter.TryRemoveLiteralSuffix(TypeUtils.XmlInt64LiteralSuffix, ref text))
                    {
                        targetValue = XmlConvert.ToInt64(text);
                    }
                    else
                    {
                        targetValue = default(Int64);
                        return(false);
                    }
                }
                else if (typeof(Single) == targetType)
                {
                    if (DomainDataServiceQueryStringConverter.TryRemoveLiteralSuffix(TypeUtils.XmlSingleLiteralSuffix, ref text))
                    {
                        targetValue = XmlConvert.ToSingle(text);
                    }
                    else
                    {
                        targetValue = default(Single);
                        return(false);
                    }
                }
                else if (typeof(Double) == targetType)
                {
                    DomainDataServiceQueryStringConverter.TryRemoveLiteralSuffix(TypeUtils.XmlDoubleLiteralSuffix, ref text);
                    targetValue = XmlConvert.ToDouble(text);
                }
                else if (typeof(Decimal) == targetType)
                {
                    if (DomainDataServiceQueryStringConverter.TryRemoveLiteralSuffix(TypeUtils.XmlDecimalLiteralSuffix, ref text))
                    {
                        try
                        {
                            targetValue = XmlConvert.ToDecimal(text);
                        }
                        catch (FormatException)
                        {
                            // we need to support exponential format for decimals since we used to support them in V1
                            decimal result;
                            if (Decimal.TryParse(text, NumberStyles.Float, NumberFormatInfo.InvariantInfo, out result))
                            {
                                targetValue = result;
                            }
                            else
                            {
                                targetValue = default(Decimal);
                                return(false);
                            }
                        }
                    }
                    else
                    {
                        targetValue = default(Decimal);
                        return(false);
                    }
                }
                else
                {
                    Debug.Assert(typeof(XElement) == targetType, "XElement == " + targetType);
                    targetValue = XElement.Parse(text, LoadOptions.PreserveWhitespace);
                }

                return(true);
            }
            catch (FormatException)
            {
                targetValue = null;
                return(false);
            }
        }
        /// <summary>Returns the 4 bits that correspond to the specified character.</summary>
        /// <param name="c">Character in the 0-F range to be converted.</param>
        /// <returns>The 4 bits that correspond to the specified character.</returns>
        /// <exception cref="FormatException">Thrown when 'c' is not in the '0'-'9','a'-'f' range.</exception>
        private static byte HexCharToNibble(char c)
        {
            Debug.Assert(DomainDataServiceQueryStringConverter.IsCharHexDigit(c), "DomainDataServiceQueryStringConverter.IsCharHexDigit(c)");
            switch (c)
            {
            case '0':
                return(0);

            case '1':
                return(1);

            case '2':
                return(2);

            case '3':
                return(3);

            case '4':
                return(4);

            case '5':
                return(5);

            case '6':
                return(6);

            case '7':
                return(7);

            case '8':
                return(8);

            case '9':
                return(9);

            case 'a':
            case 'A':
                return(10);

            case 'b':
            case 'B':
                return(11);

            case 'c':
            case 'C':
                return(12);

            case 'd':
            case 'D':
                return(13);

            case 'e':
            case 'E':
                return(14);

            case 'f':
            case 'F':
                return(15);

            default:
                throw new InvalidOperationException();
            }
        }