Почему помощники синтаксического анализа не стали проще в использовании? [закрытый]


Учитывая, что команда .NET заявила (я найду источник...) что они сожалеют о разработке методов синтаксического анализа примитивного типа (например,Int32.TryParse(String s, out Int32 result)) почему они не были обновлены с более очевидным и удобным для клиента вариантом?

Версия Фреймворка:

Int32? numValue;
Int32 placeHolder;
if (! Int32.TryParse("not a number", out placeHolder))
    numValue = 10;

Улучшенная Версия:

var numValue = Int32.Parse("not a number", 10);

Где сигнатура для улучшенного метода синтаксического анализа:

public static Int32? Parse(String s, Int32? defaultValue = null);

И это может иметь наивную реализацию:

public static Int32? Parse(String s, Int32? defaultValue = null) {
    Int32 temp;
    return ! Int32.TryParse(s, out temp)
        ? defaultValue
        : temp;
}
2 2

2 ответа:

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

Некоторые соображения могут быть следующими:

  1. изменение методов будет представлять собой большое разрушающее изменение в существующие кодовые базы с очень небольшим (спорным, если таковые имеются) выигрышем. Некоторые можно было бы возразить, что это было бы ущербом по причинам, приведенным ниже.
  2. типы, допускающие значение null коробка обернутая обернуть базового значения вызывает (незначительные) снижение производительности всегда, даже если вы ожидаете, что ваш разбор будет успешным и не хотите, чтобы нуль-тип в любом случае.
  3. Если Вы знаете , что ваш ввод считается действительным, то Parse метод создает исключения для исключительного случая , что входные данные недопустимый. Это, как правило, более эффективно, так как у нас нет дополнительных код обработки ошибок для тех случаев, когда он нам не нужен, и ожидается от проектная точка зрения. Если вы планируете вести дело о недействительности, вот что TryParse - это для.
  4. путаница между int Parse(string, int? defaultValue) и int Parse(string), главным образом в отношении их обработки ошибок. Уведомление Я удалил необязательную часть первого метода, иначе это было бы не имеет смысла иметь оба метода (вы никогда не сможете вызвать ваш метод без явной передачи в null). В этот момент, он было бы немного запутанно, как одна перегрузка бросает исключение на неудача, в то время как другой-нет. Есть несколько исключений к этому, например: тип.GetType но они ... вообще редко, и в таких случаях они используют явно именованный параметр , указывающий, что он будет или не будет вызывать исключение.
  5. Еще одно преимущество TryParse в том, что он хорош собой явный через свой API для обработки результата pass / fail. Скорее чем магическое число / результат (null), указывающее на неудачу, он возвращает aотдельное значение true/false. Теперь, некоторые механизмы делают это (String.IndexOf например, возвращая -1) Так что это спорно, если это хорошо или плохо. В зависимости от вашей практики, использование возвращаемого значения true/false может быть проще, или волшебный null результат может быть. Но они решили я думаю не мутить воды с двумя методами делают то же самое, но с помощью немного другие сигнатуры / возвращаемые значения.
  6. Еще одно соображение заключается в том, насколько распространеныnullable типы значений. Являются вы действительно используете Int32? во многих местах? Или это только для того, чтобы обработка ошибок / входных данных? В по моему опыту, нулевые значения-это в основном используется для ввода-вывода баз данных (и даже тогда, не так часто). Единственный другие времена могли бы быть для ввода из недоверенных источников, которые будут только для начального сопряжения; весь базовый код будет по-прежнему наберите против не-nullable Int32. В таком случае у вас есть два методы, оригинальные:

    int input;
    if (TryParse(someString, out input))
        DoSomethingValid(input); //valid! Do something
    else
        ErrorMessage()//not valid, error!
    

    Или ваше предложение:

    int? input = Parse(someString)
    if (input != null)
        DoSomethingValid(input.GetValueOrDefault())//valid! Do something
    else
        ErrorMessage()//not valid, error!
    
    Обратите внимание, какпохожи оба. Ваше предложение действительно обеспечивает очень мало, если что угодно в этом деле. Также обратите внимание на использование GetValueOrDefault(), это на самом деле более быстрый / лучший способ получить доступ к обернутому значению , Если вы знаете, что оно ненулевое, но редко (в по крайней мере, из того, что я вижу в интернете) используется ли он над Value средство доступа. Если BCL добавил / изменил метод Parse, Как вы предположим, я думаю, что много людей будут напрасно бить аксессор Value.

    Я не могу комментировать конкретно случаи использования nullable ценности существенно на протяжении всего дизайна приложения и / или его слоев, но по моему опыту они редко используются или должны использоваться редко (для меня это запах кода почти на уровне "stringly-typed" данных)

В конечном счете, я считаю, что Часть причины, по которой методы расширения были добавлены (помимо Linq), заключалась в том, чтобы позволить пользователям катить свой собственный API по мере необходимости. В вашем случае вы можете легко добавить метод расширения, чтобы получить синтаксис, который вы хочу:

public static Int32? Parse(this String s, Int32? defaultValue = null)
{
    Int32 temp;
    return !Int32.TryParse(s, out temp)
        ? defaultValue
        : temp;
}

string validString = "1";
int? parsed = validString.Parse(); //1
int? failParsed = "asdf".Parse(9); //9
Команды обычно выступают за сохранение статус-кво, и дополнения должны обеспечить достаточно значительное преимущество для добавления в систему, и команда также рассматривает, какие обходные пути уже существуют в API как есть. Я бы предположил, что, учитывая опцию метода расширения, это не так уж и важно, чтобы изменить API, учитывая его значимый разрывающий характер.

Эта подпись:

public static Int32? Parse(String s, Int32? defaultValue = null);

Будет конфликтовать с существующей перегрузкой Parse(string s), потому что нет способа отличить их друг от друга, если необязательный аргумент не указан. Существующие методы, вероятно, никогда не будут изменены или удалены, потому что это нарушит совместимость с существующим кодом.

Однако можно было бы создать перегрузки TryParse, которые не принимают параметр out int value:

public static int? TryParse(string s)

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

string s = ...
int value = int.TryParse(s) ?? 0;