2014-11-10 2 views
3

У меня есть сеанс, который содержит определенные целые значения, которые индексируются с данными элементами управления. Как правило, следующий будет работать нормально:Whoa, что TryParse

int value; 
int.TryParse(Session["Key"].ToString(), out value); 

Однако мне необходимо учитывать нуль. Если, если string не удался, по умолчанию из вернет null. Кроме того я заметил, что int.TryParse не работает с:

int? value = null; 
int.TryParse(Session["Key"].ToString(), out value); 

Так как же вы можете попробовать что синтаксический анализ, если не удается это приводит к нулевой?

Я нашел это question и Developer Network Microsoft диктует:

Когда этот метод возвращает, содержит целое значение, эквивалент числа, содержащегося в секундах, если преобразование удалось, или ноль, если преобразование не выполнено. Преобразование завершается с ошибкой, если параметр имеет значение null или String.Empty, не соответствует правильному формату, или представляет число, меньшее чем Min Value или больше Max Value. Этот параметр передается неинициализированным.

Который ясно говорит, если int.TryParse выходит из строя целое будет содержать значение, равное нулю. В случае моего использования значение нуля может быть допустимым. Так что мне нужно null, любые мысли?

+1

Почему бы не выполнять регулярные работы? '(int?) (Session [" Key "])' –

+0

@AlexeiLevenkov Я мог бы потенциально сделать: 'Session [" Key "] как int?', где он возвращает значение NULL, если он терпит неудачу. – Greg

+0

Я немного смущен - я полагаю, вы поместили nullable в состояние сеанса - так что будет либо допустимое значение «int?», Либо отсутствие ключа - оба должны работать с cast/as успешно. Я не вижу случая, когда «он терпит неудачу» ... –

ответ

9

Sure; использовать возвращаемое значение int.TryParse (который возвращает, если преобразование успешно или нет):

int? retValue = null; 
int parsedValue = 0; 

if (int.TryParse(Session["Key"].ToString(), out parsedValue)) 
    retValue = parsedValue; 
else 
    retValue = null; 

return retValue; 

Немного Verbose Я допускаю, но вы можете обернуть его в функции.

6
int tmp; 
int? value = int.TryParse(Session["Key"].ToString(), out tmp) ? (int?)tmp : null; 
+0

Этот код явно бросает исключение NullReferenceException, когда ключ не существует/имеет значение «null» (точно такое же поведение, какое требует OP, но не обязательно то, что может понадобиться другим пользователям. Остерегайтесь). –

+0

@AlexeiLevenkov Нет сомнений, но, я думаю, это не подлежит рассмотрению этого вопроса. – AlexD

1

Проблема заключается в слове «null». Что это значит? null может означать, что значение неопределимо, исключение было выбрано просто, что значение равно null или другому контекстуальному значению. Ваш вопрос - прекрасный пример, потому что вы, сами, произвольно заявляете, что, по вашему мнению, null означает, что разбор строки не прошел.

Парадигма TryParse от Microsoft отличная, но для ограниченного использования. Рассмотрим эти сценарии:

  • строка == "89"
  • строка == NULL
  • строка == "Hello World"
  • строка == ""
  • строка == "2147483650"

Однако, ваши единственные варианты - назначить Integer или Null на ваш вывод и вернуть true или false.

Предполагая, что это сработало, что вы собираетесь делать с этой информацией?Что-то вроде этого?

int? value = null; 
if (int.TryParse(Session["Key"].ToString(), out value)) { 
    if (value == null) 
     // Handle "Appropriate" null 
    else 
     // Handle appropriate numeric value 
} 
else { 
    // Note: value == null here, and TryParse failed 
    // Handle null... 
    // What if the reason it failed was because the number was too big? 
    // What if the string was Empty and you wanted to do something special? 
    // What if the string was actually junk? Like "(423)322-9876" ? 
    // Long-Story Short: You don't know what to do here without more info. 
} 

Рассмотрим пример NullableInt TryParse:

public bool TryParseNullableInt(string input, out int? output) 
{ 
    int tempOutput; 
    output = null; 
    if (input == null) return true; 
    if (input == string.Empty) return true; // Would you rather this be 0? 

    if (!int.TryParse(input, out tempOutput)) 
     return false; // What if string was "2147483650"... or "Twenty Three"? 
    output = tempOutput; 

    return true; 
} 

Одним из решений является использование перечисления TryParse вместо булевой TryParse:

public ParseStatus TryParseNullableInt(string input, out int? output) 
{ 
    int tempInteger; 
    output = null; 
    if (input == null) return ParseStatus.Success; 
    if (input == string.Empty) { output = 0; return ParseStatus.Derived; } 

    if (!int.TryParse(input, out tempInteger)) { 
     if (ParseWords(input, out tempInteger)) { // "Twenty Three" = 23 
      output = tempInteger; 
      return ParseStatus.Derived; 
     } 
     long tempLong; 
     if (long.TryParse(input, out tempLong)) 
      return ParseStatus.OutOfRange; 
     return ParseStatus.NotParsable; 
    } 
    output = tempInteger; 

    return ParseStatus.Success; 
} 

Другой проблемой является существование переменной out , Ваш третий вариант заключается в использовании описательной монады, что-то вроде этого:

public Maybe<int?> TryParseNullableInt(string input) 
{ 
    if (input == null) return Maybe.Success(null); 
    if (input == string.Empty) { return Maybe.Derived(0); } 

    int tempInteger; 
    if (!int.TryParse(input, out tempInteger)) { 
     if (ParseWords(input, out tempInteger)) { // "Twenty Three" = 23 
      return Maybe.Derived(tempInteger); 
     } 
     long tempLong; 
     if (long.TryParse(input, out tempLong)) 
      return Maybe.OutOfRange(); 
     return Maybe.NotParsable(); 
    } 

    return Maybe.Success(tempInteger); 
} 

Вы можете использовать монады как Single-перечислимые значения, или как так:

Maybe<int?> result = TryParseNullableInt("Hello"); 
if (result.HasValue) { 
    if (result.Status == ParseStatus.Success) 
     // Do something you want... 
    else if (result.Status == ParseStatus.Derived) 
     // Do something else... more carefully maybe? 
} 
else if (result.Status == ParseStatus.OutOfRange) 
    MessageUser("That number is too big or too small"); 
else if (result.Status == ParseStatus.NotParsable) 
    // Do something 

С Монадой, и, возможно, счетными TryParses, теперь у вас есть вся необходимая информация из описательного возврата, и никто не должен угадать, что может означать null.