Скажите, если строка для double / float/int / short / byte находится вне диапазона


У меня есть следующее:

string outOfRange = "2147483648"; // +1 over int.MaxValue

Очевидно, что если у вас есть что-то, кроме числа, это не сработает:

var defaultValue = 0;
int.TryParse(outOfRange, out defaultValue);

Мой вопрос таков: поскольку это число, и оно не сработает, когда вы int.TryParse(), Как вы можете сказать, что оно не сработало, потому что строка вышла за пределы контейнера, в котором она хранится?

8 7

8 ответов:

Я попытаюсь проанализировать, если это не удастся, затем попытаюсь проанализировать значение более высокой емкости. Если более высокое значение емкости проходит синтаксический анализ, то вы знаете, что оно находится вне диапазона. Если он также терпит неудачу,то это плохой ввод.

string outOfRange = "2147483648"; // +1 over int.MaxValue
int result;
if (!Int32.TryParse(outOfRange, out result))
{
    long rangeChecker;
    if (Int64.TryParse(outOfRange, out rangeChecker))
        //out of range
    else
        //bad format
}
К сожалению, я не думаю, что есть способ сделать это обобщенно для любого типа; вам придется написать реализацию для всех типов. Так, например, что делать для Int64? Может быть, использовать BigInteger вместо:
string outOfRange = "9223372036854775808"; // +1 over Int64.MaxValue
long result;
if (!Int64.TryParse(outOfRange, out result))
{
    BigInteger rangeChecker;
    if (BigInteger.TryParse(outOfRange, out rangeChecker))
        //out of range
    else
        //bad format
}

Редактировать: double значения с плавающей запятой могут будьте веселее, так как AFAIK, там нет "BigDecimal", и вы можете также учитывать значения, которые приближаются к 0 в самом крайнем случае (не уверен в этом). Возможно, вы могли бы сделать вариацию на проверку BigInteger, но вам также придется учитывать десятичные точки (вероятно, простое регулярное выражение будет лучше здесь иметь только числа, необязательный отрицательный знак и только одну, самое большее десятичную точку). Если есть какие-либо десятичные точки, вы должны были бы усечь их и просто проверить целочисленная часть строки.

EDITx2: вот довольно уродливая реализация для проверки значений double:

// +bajillion over Double.MaxValue
string outOfRange = "90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.1";
double result;
if (!Double.TryParse(outOfRange, out result))
{
    string bigIntegerInput = outOfRange;

    if (!Regex.IsMatch(bigIntegerInput, @"^-?[0-9]\d*(\.\d+)?$"))
        //bad format

    int decimalIndex = bigIntegerInput.IndexOf('.');
    if (decimalIndex > -1)
        bigIntegerInput = bigIntegerInput.Substring(0, decimalIndex);

    BigInteger rangeChecker;
    if (BigInteger.TryParse(bigIntegerInput, out rangeChecker))
        //out of range
    else
        //bad format
}
Но, честно говоря, на данный момент я думаю, что мы просто сошли с ума. Если у вас нет какого-то реального узкого места производительности, или ваше приложение имеет значения вне диапазона, вводимые часто, Вам может быть лучше просто поймать их нечетное время, как это происходит в этом ответе или, возможно, более просто, применяя регулярное выражение к входным данным. В моем последнем примере я мог бы также просто бросить делать регулярное выражение в любом случае (но я не знаю, с моей головы, являются ли реализации TryParse более мягкими, позволяя экспоненциальную / научную нотацию. Если это так, регулярное выражение должно было бы охватить и их)

Я бы пошел с решением Try/Catch для этого сценария.

        string outOfRange = "2147483648";
        try
        {
            int.Parse(outOfRange);
        }
        catch (OverflowException oex)
        {

        }
        catch (Exception ex)
        { }
Я знаю, что большинство людей здесь рекомендовали бы избегать этого, но иногда мы просто должны использовать его (или мы не должны, но это просто сэкономит нам много времени).
вот небольшой пост об эффективности Try/Catch.

Может разобрать до десятичной, а затем проверить диапазон, избегает try / catch

string s = "2147483648";
decimal.Parse(s) > int.MaxValue;
string outOfRange = "2147483648"; // +1 over int.MaxValue
int value;
if(! int.TryParse(outOfRange, out value)) {
    try {
        int.Parse(defaultValue);
    } catch(OverflowException e) {
        // was overflow
    } catch(Exception e) {
        // was other reason
    }
}

Предполагая, что существует несколько случаев, когда число слишком велико, накладные расходы на выбрасывание и перехват исключений могут быть терпимыми, поскольку обычные случаи обрабатываются более быстрым методом TryParse без привлечения исключений.

Это будет работать аналогично для других числовых типов данных, таких как floats, ...

Можно попробовать выполнить синтаксический анализ с помощью BigInteger.

BigInteger bigInt;
bool isAnOutOfRangeInt = BigInteger.TryParse(input, out bigInt)
                         && (bigInt > int.MaxValue || bigInt < int.MinValue);
// if you care to have the value as an int:
if (!isAnOutOfRangeInt)
{
    int intValue = (int)bigInt;
}

Используйте обычный Parse вместо TryParse. А затем используйте его внутри try / catch, потому что он даст вам соответствующее исключение. Смотрите это для деталей: http://msdn.microsoft.com/en-us/library/b3h1hf19.aspx исключение, которое вы ищете, - этоOverflowException .

Я бы посмотрел на использование системы .Преобразовать.ToInt32 (String) как механизм для преобразования вещей; а именно потому, что OverflowException уже был реализован для вас.

Это удобно, потому что вы можете сделать что-то простое, например

 try 
 {
      result = Convert.ToInt32(value);
      Console.WriteLine("Converted the {0} value '{1}' to the {2} value {3}.",
                    value.GetType().Name, value, result.GetType().Name, result);
 }
 catch (OverflowException) 
 {
      Console.WriteLine("{0} is outside the range of the Int32 type.", value);
 }   
 catch (FormatException) 
 {
      Console.WriteLine("The {0} value '{1}' is not in a recognizable format.",
                    value.GetType().Name, value);
 }   

И логика уже является частью стандартной системной библиотеки.

Прямым путем было бы вместо этого использовать Int32.Parse (string s) и catch OverflowException;

OverflowException
s представляет собой число меньше, чем minvalue или больше, чем maxvalue.