Почему T.TryParse не возвращает Nullable <T>
Насколько я знаю, int.TryParse(string, out int)
существует с Framework 2.0. Таким образом, int?
.
Есть ли причина использовать параметр out
вместо того, чтобы возвращать int?
с HasValue
, установленным в true
of false
, в зависимости от способности конвертировать?
Ответы
Ответ 1
Я не могу рассказать о реальных причинах, но я вижу три возможные причины:
1) Nullable types были введены в .NET 2.0, а первые TryParse
методы были уже с .NET 1.1. Таким образом, когда вводились типы с нулевым значением, было слишком поздно для такого изменения API; и новые классы не будут реализовывать TryParse
иначе, потому что шаблон уже установлен.
2) Не все типы могут использоваться с структурой Nullable
, могут использоваться только типы значений. Однако существуют методы, следующие за шаблоном Try*
, которые должны возвращать ссылочные типы. Например, словарь может полностью законно содержать null
как элемент, поэтому его метод TryGetValue
требует дополнительного способа выразить, что ключ не найден.
3) Способ записи Try*
-методов, можно написать такой код:
int myValue;
if (int.TryParse("42", out myValue)) {
// do something with myValue
}
// do something else
}
Теперь, представьте, если TryParse
вернул int?
. Вы можете либо избавиться от переменной myValue
и потерять результат:
if (int.TryParse("42").HasValue) {
// do something with ... what? You didn't store the conversion result!
}
// do something else
}
Или вы можете добавить переменную с нулевым значением:
int? myValue = int.TryParse("42");
if (myValue.HasValue) {
// do something with myValue.Value
}
// do something else
}
Это больше не является преимуществом по сравнению с текущей версией, а вместо этого требует записи myValue.Value
в некоторых более поздних экземплярах, где в противном случае достаточно простого value
. Обратите внимание, что во многих случаях вам нужна только информация о том, была ли операция успешной для оператора if
.
Ответ 2
Простая причина в том, что, когда int.TryParse
был добавлен к языку, Nullable<T>
не существовало.
В это сообщение в блоге Эрика Липперта, есть строка внизу, которая гласит:
Решение состоит в том, чтобы написать собственную версию метода TryParse для расширения, как это было бы написано, если бы были доступны типы с нулевыми значениями
который дает понять, что типы с нулевым значением недоступны для использования в исходной реализации TryParse
. Эрик Липперт был в команде, которая написала компилятор С#, поэтому я бы сказал, что это довольно авторитетный источник.
Ответ 3
Вот цитата из блога Джулии Лерман (Back from 2004):
Я играл с nullable
в битках предварительного просмотра в марте, но еще не в мае, и разочаровался в текущем (но ожидаемом серьезном улучшении командой bcl team!!!), когда сравнивал использование nullable<t>
над текущими вариантами. Так, например, со значениями типов:
сравнение myNullableInt.HasValue
to (в VB) myInt < 0
или с ссылочными типами
сравнивая myNullableThing.HasValue
с "if not myThing=null
"
тип с нулевым значением в настоящее время намного медленнее. Я был , обещанный несколькими членами команды BCL, что план должен сделать значение NULL MUCH более эффективным.
Мне также был дан намек на то, что в будущем возможно следующее:
Nullable<T> Parse(string value);
Nullable<Int32> i = Int32.Parse( some String );
И будет более результативным, чем TryParse
. Так что это тоже будет интересно.
Я предполагаю, что, как всегда, преимущество перевешивает стоимость.
В любом случае, в предстоящем С# vNext вы можете сделать:
DateTime.TryParse(s, out var parsedDateTime);
Поворот TryParse в один лайнер.
Ответ 4
Еще одна возможная причина:
Generics для .NET и С# в их текущей форме почти не произошло: это был очень близкий вызов, и функция почти не делала разрезание для Whidbey (Visual Studio 2005). Такие функции, как запуск CLR-кода в базе данных, получили более высокий приоритет.
...
В конечном счете, модель стирания дженериков была бы принята, как и для Java, так как команда CLR никогда не использовала бы разработку дженериков в VM без внешней помощи.
источник: http://blogs.msdn.com/b/dsyme/archive/2011/03/15/net-c-generics-history-some-photos-from-feb-1999.aspx
Моя точка зрения: большинство изменений в BCL (или, по крайней мере, те, которые напрямую не связаны с дженериками), вероятно, необходимы для работы как с дженериками, так и без них, в случае, если в окончательной RTM была отключена функция.
Конечно, это также имеет смысл с точки зрения клиентского клиента: все потребляющие языки (нормально, их было не так много) в идеале могли бы их использовать, а параметры out
были не такими, как как универсальные.
Ответ 5
Что касается причин, мы можем только догадываться, но возможны некоторые причины:
Накладные расходы на присвоение: значение в коробке несет некоторые (небольшие) служебные данные по производительности по встроенному типу.
Нет реальных выигрышей:
int res;
if int.TryParse("one", out res) {
//something
}
не намного хуже, чем
int? res = int.TryParse("one");
if (res.HasValue){
int realres = res.Value
//something
}