Почему TryParse именно так? - PullRequest
1 голос
/ 19 июня 2020

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

Например, если мы возьмем базовую c реализацию Parse, возвращаемое значение будет проанализированным вводом:

int parsedValue = int.Parse(input);

Это работает нормально, пока не получит значение, которое не может выполнить синтаксический анализ, и в этот момент он совершенно разумно вызывает исключение. Для меня вариант - либо обернуть синтаксический анализ чем-то вроде блока try-catch для обработки исключения и условия для установки значения по умолчанию, либо просто использовать TryParse, чтобы C# сделал все это за меня. Только вот TryParse работает не так. Приведенный выше пример теперь выглядит так:

bool parseSucceeded = int.TryParse(input, out int parsedValue);

Чтобы назначить его таким же образом, как Parse, я заключил его в тернарное условное выражение с parsedValue и значением по умолчанию (в данном случае , 0) в качестве результатов true и false соответственно:

int parsedValue = int.TryParse(input, out parsedValue) ? parsedValue : 0;

Но мне все еще кажется, что я упускаю суть с TryParse, если я просто работаю над его поведением по умолчанию, например этот. Я прочитал отличный ответ Тима Шмелтера , в котором он показывает его внутреннюю работу, из чего я могу предположить, что он возвращает логическое значение, потому что это легче внутренне, чем передавать его во всех различных местах, которые он в настоящее время возвращает. Но я не уверен в этом и не уверен, что правильно понимаю его намерения. Я также пробовал читать документацию для него, но замечания не проясняют мою путаницу (я не думаю, что они даже достаточно ясно видят различия с Parse, например, изменение типа возвращаемого значения) .

Я правильно понимаю, или я что-то упустил?

Ответы [ 3 ]

3 голосов
/ 19 июня 2020

Конечно, это могло быть реализовано как

int TryParse(string input, out bool succeeded)
{

}

Но, как упоминалось в комментарии, общий вариант использования функции:

string input;
int parsedValue;
if(int.TryParse(input, out parsedValue))
{
    // use parsedValue here
}

С подписью, которую вы предлагаете , этот код теперь будет:

string input;
bool succeeded;
int parsedValue = int.TryParse(input, out succeeded)
if(succeeded)
{
    // use parsedValue here
}

Таким образом, здесь больше кода без каких-либо функциональных преимуществ. Кроме того, с вашим тернарным оператором, если синтаксический анализ не удался, вы просто устанавливаете нулевое значение, что не нужно, поскольку его значение по умолчанию равно 0. Вы можете просто сделать:

int parsedValue; 
int.TryParse(input, out parsedValue);

Если синтаксический анализ не удался, parsedValue будет иметь значение 0; (Я также сомневаюсь, что / как вы различаете guish между фактическим результатом 0 и неудачным синтаксическим анализом, но я уверен, что у вас есть причина).

Итак нет технической причины, по которой подпись такая, какая есть; это дизайнерское решение, подходящее для наиболее распространенных случаев использования.

Конечно, теперь с кортежами в C# 7 вы могли бы иметь:

(int parsedValue, bool succeeded) = int.TryParse(input);

но опять же, это небольшое функциональное преимущество, и вы не можете встраивать TryParse в оператор if.

2 голосов
/ 19 июня 2020

Потому что логически вы захотите проверить, что TryParse преуспел, прежде чем пытаться использовать значение out.

Так что это более кратко:

if (int.TryParse(input, out int parsedValue)}
{
    // Do something with parsedValue
}

Чем это:

int parsedValue = int.TryParse(input, out bool succeded);
if (succeeded)
{
    // Do something with parsedValue
}
1 голос
/ 19 июня 2020

Я думаю, большая часть вашей путаницы связана с неправильным названием метода:

int parsedValue = int.Parse("42");

Это имеет смысл, дайте мне целочисленное представление строки.

int parsedValue = int.TryParse(input);

Это имеет смысл как расширение концепции: ввод может быть «42» или «Освальд», но если это число, мне нужно это число.

В 2020 году я думаю, что лучшим именем было бы CanParse(string input, out int result).

  1. Это лучше соответствует руководствам по стилю и соглашениям об именах, где возвращаемое bool должно быть названо Is, Has или Can.
  2. Это лучше соответствует тому, как мы используем TryParse в 99% случаев:

    if (int.CanParse(input, out int result)) { return result * 10; }

Но если я чувствую, что текущее имя имеет смысл, проблема в том, что я Предположим, он пытался решить: Чтобы избавиться от следующего шаблонного кода:

int result;
bool hasValidNumber = false;

try
{
    result = int.Parse(input);
    hasValidNumber = true;
}
catch
{
    // swallow this exception
}
if (hasValidNumber)
{
   // do things with result
}
else
{
   // use a default or other logic
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...