/// <summary>
        ///     Infer from the input string what type it is, and return the field as that type
        ///     (int, long, decimal, double, bool or string)
        /// </summary>
        /// <param name="input">the input sting</param>
        /// <returns>the value cast to the type it could be parsed into</returns>
        public static object CastToInferredType(this string input)
        {
            var target = input;

            // we infer hex numbers to be signed; size in bytes determines which return value to be used
            // (byte, short, int, long)
            if (NumericFunctions.TryParseHex(input, true, out var hexValue))
            {
                target = hexValue.ToString();
            }
            if (int.TryParse(target, out var intValue))
            {
                return(intValue);
            }
            if (long.TryParse(target, out var longValue))
            {
                return(longValue);
            }
            if (decimal.TryParse(target, out var decimalValue))
            {
                return(decimalValue);
            }
            if (double.TryParse(target, out var doubleValue))
            {
                return(doubleValue);
            }
            if (bool.TryParse(target, out var boolValue))
            {
                return(boolValue);
            }
            return(input);
        }
        private static object ChangeType(object value, Type targetType)
        {
            var source = value;

            // if we want a numeric result and we have a hex value, convert the hex to long first.
            if (targetType.IsNumeric() &&
                NumericFunctions.TryParseHex(value?.ToString(), targetType.IsSigned(), out var hexValue))
            {
                source = hexValue;
            }
            try
            {
                return(Convert.ChangeType(source, targetType, InvariantCulture));
            }
            catch (Exception e) when(e is FormatException || e is InvalidCastException)
            {
                try
                {
                    return(Convert.ChangeType(source, targetType, CurrentUICulture));
                }
                catch (Exception fe) when(fe is FormatException || fe is InvalidCastException)
                {
                    throw new FormatException(Invariant($"Could not convert '{value}' to {targetType.Name}"), fe);
                }
            }
        }
        /// <summary>
        ///     Get the type that the input value can be parsed into (int, long, double, bool, string)
        /// </summary>
        /// <param name="value">the value to be examined</param>
        /// <returns>The type it was successfully parsed into</returns>
        public static Type InferType(this object value)
        {
            var stringValue = value?.ToString();

            // we infer hex numbers to be signed, see CastToInferredType
            if (NumericFunctions.TryParseHex(stringValue, true, out var hexValue))
            {
                stringValue = hexValue.ToString();
            }
            if (int.TryParse(stringValue, NumberStyles.Integer, InvariantCulture, out _))
            {
                return(typeof(int));
            }
            if (long.TryParse(stringValue, NumberStyles.Integer, InvariantCulture, out _))
            {
                return(typeof(long));
            }
            if (double.TryParse(stringValue, NumberStyles.Any, InvariantCulture, out _))
            {
                return(typeof(double));
            }
            if (double.TryParse(stringValue, NumberStyles.Any, CurrentUICulture, out _))
            {
                return(typeof(double));
            }
            return(bool.TryParse(stringValue, out _) ? typeof(bool) : typeof(string));
        }