Почему помощники синтаксического анализа не стали проще в использовании? [закрытый]
Учитывая, что команда .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 ответа:
Я не уверен, что будет окончательный ответ на этот вопрос, если кто-то из команды BCL не расскажет историю.
Некоторые соображения могут быть следующими:
- изменение методов будет представлять собой большое разрушающее изменение в существующие кодовые базы с очень небольшим (спорным, если таковые имеются) выигрышем. Некоторые можно было бы возразить, что это было бы ущербом по причинам, приведенным ниже.
- типы, допускающие значение null
коробка обернутаяобернуть базового значения вызывает (незначительные) снижение производительности всегда, даже если вы ожидаете, что ваш разбор будет успешным и не хотите, чтобы нуль-тип в любом случае.- Если Вы знаете , что ваш ввод считается действительным, то
Parse
метод создает исключения для исключительного случая , что входные данные недопустимый. Это, как правило, более эффективно, так как у нас нет дополнительных код обработки ошибок для тех случаев, когда он нам не нужен, и ожидается от проектная точка зрения. Если вы планируете вести дело о недействительности, вот чтоTryParse
- это для.- путаница между
int Parse(string, int? defaultValue)
иint Parse(string)
, главным образом в отношении их обработки ошибок. Уведомление Я удалил необязательную часть первого метода, иначе это было бы не имеет смысла иметь оба метода (вы никогда не сможете вызвать ваш метод без явной передачи вnull
). В этот момент, он было бы немного запутанно, как одна перегрузка бросает исключение на неудача, в то время как другой-нет. Есть несколько исключений к этому, например: тип.GetType но они ... вообще редко, и в таких случаях они используют явно именованный параметр , указывающий, что он будет или не будет вызывать исключение.- Еще одно преимущество
TryParse
в том, что он хорош собой явный через свой API для обработки результата pass / fail. Скорее чем магическое число / результат (null
), указывающее на неудачу, он возвращает aотдельное значение true/false. Теперь, некоторые механизмы делают это (String.IndexOf
например, возвращая -1) Так что это спорно, если это хорошо или плохо. В зависимости от вашей практики, использование возвращаемого значенияtrue/false
может быть проще, или волшебныйnull
результат может быть. Но они решили я думаю не мутить воды с двумя методами делают то же самое, но с помощью немного другие сигнатуры / возвращаемые значения.Еще одно соображение заключается в том, насколько распространеныnullable типы значений. Являются вы действительно используете
Int32?
во многих местах? Или это только для того, чтобы обработка ошибок / входных данных? В по моему опыту, нулевые значения-это в основном используется для ввода-вывода баз данных (и даже тогда, не так часто). Единственный другие времена могли бы быть для ввода из недоверенных источников, которые будут только для начального сопряжения; весь базовый код будет по-прежнему наберите против не-nullableInt32
. В таком случае у вас есть два методы, оригинальные: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 по мере необходимости. В вашем случае вы можете легко добавить метод расширения, чтобы получить синтаксис, который вы хочу:
Команды обычно выступают за сохранение статус-кво, и дополнения должны обеспечить достаточно значительное преимущество для добавления в систему, и команда также рассматривает, какие обходные пути уже существуют в API как есть. Я бы предположил, что, учитывая опцию метода расширения, это не так уж и важно, чтобы изменить 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
Эта подпись:
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;