В последнее время у меня была небольшая дискуссия с коллегой. Мы специально используем C #, но это может относиться к любому языку с обнуляемыми типами. Скажем, например, у вас есть значение, которое представляет максимум. Однако это максимальное значение не является обязательным. Я утверждаю, что обнуляемое число будет предпочтительнее. Мой коллега поддерживает использование нуля, ссылаясь на прецедент. Конечно, такие вещи, как сетевые сокеты, часто используют ноль для представления неограниченного времени ожидания. Если бы я писал сегодня код, работающий с сокетами, я бы лично использовал значение, которое можно обнулять, так как я чувствую, что это будет лучше отражать тот факт, что тайм-аут НЕТ.
Какое представление лучше? Оба требуют проверки условия для значения, означающего «нет», но я считаю, что обнуляемый тип передает намерение немного лучше.
источник
Ответы:
Рассмотреть возможность:
Язык,
Фреймворк,
Контекст.
1. Язык
Использование ∞ может быть решением для максимума.
JavaScript, например, имеет бесконечность. C # не ¹
Ада, например, имеет диапазоны. C # нет.
В C # есть
int.MaxValue
, но вы не можете использовать его в вашем случае.int.MaxValue
максимальное целое число, 2 147 483 647. Если в вашем коде у вас есть максимальное значение чего-либо, например максимально допустимое давление, прежде чем что-то взорвется, использование 2 147 483 647 не имеет смысла.2. Рамки
.NET Framework довольно противоречив в этом вопросе, и его использование магических ценностей может быть подвергнуто критике.
Например,
"Hello".IndexOf("Z")
возвращает магическое значение-1
. Это может облегчить (не так ли) манипулирование результатом:вместо использования пользовательской структуры:
но совсем не интуитивно. Почему
-1
и нет-123
? Начинающий может также ошибочно думать, что это0
означает «Не найден» или просто опечатка(position >= 0)
.3. Контекст
Если ваш код связан с таймаутами в сетевых сокетах, использование чего-то, что использовалось всеми в течение десятилетий для обеспечения согласованности, не является плохой идеей . Тем более,
0
что тайм-аут очень ясен: это значение, которое не может быть нулевым. Использование собственного класса в этом случае может усложнить понимание:Duration
0, еслиIsTimeoutEnabled
это правда?IsTimeoutEnabled
false, что произойдет, если я установлюDuration
на 100?Это может привести к множественным ошибкам. Представьте себе следующий фрагмент кода:
Операция длится десять секунд. Можете ли вы увидеть, что не так с этим кодом, не читая документацию
Timeout
класса?Вывод
null
хорошо выражает мысль о том, что значение не здесь. Это не предусмотрено. Нет в наличии. Это ни число, ни ноль / пустая строка, ни что-либо еще. Не используйте его для максимальных или минимальных значений.int.MaxValue
тесно связан с самим языком. Не используйтеint.MaxValue
для ограничения максимальной скоростиVehicle
класса или максимально приемлемой скорости для самолета и т. Д.Избегайте магических значений, как
-1
в вашем коде. Они вводят в заблуждение и приводят к ошибкам в коде.Создайте свой собственный класс, который будет более простым, с указанием минимальных / максимальных значений. Например
VehicleSpeed
может иметьVehicleSpeed.MaxValue
.Не следуйте никаким предыдущим рекомендациям и используйте магические значения, если это десятилетие является общим соглашением в очень специфической области, используемой большинством людей, пишущих код в этой области.
Не забудьте смешать подходы. Например:
¹ Вы можете создать свой собственный тип, который включает в себя бесконечность. Здесь я говорю только о нативном
int
типе.источник
int
недостаточно выражает тип, чтобы ограничить проблему, рассмотрите новую структуру с большим количеством информации (например, const экземпляры структуры, которые представляют магические значения, или перечисление на нем для указания). Или подумайте о программировании по контракту или о некоторых других решениях, но я думаю, что пользовательская структура является наиболее простой.Нуль не лучше магического числа.
Важно НАИМЕНОВАТЬ значения, которые имеют магические эффекты, если вам нужно иметь такие значения, и убедиться, что определения этих имен находятся там, где их увидит любой, кто сталкивается с магическим значением и wtf.
источник
MAGIC_NUMBER
код всегда следует избегать везде, где это возможно.null
это гораздо более четкое выражение намерения.источник
В C # многие классы CLR имеют статический
Empty
член:System.String.Empty
System.EventArgs.Empty
System.Guid.Empty
System.Drawing.Rectangle.Empty
System.Windows.Size.Empty
Это избавляет вас от необходимости помнить, использовать ли магическое значение или использовать ноль для создания пустого объекта.
Но что, если вы имеете дело с простым типом значения, таким как
int
? В этом случае подумайте, не стали ли вы жертвой Primitive Obsession . Вполне возможно, что ваше внешне простое числовое свойство выиграет от своего собственного класса или структуры, что позволит вам указатьEmpty
член, а также добавить другое поведение, специфичное для этого типа значения.источник
В этом случае нулевое значение - отличный способ указать, что максимума нет. Обычно, когда особый случай означает, что рассматриваемое значение не применяется, что вы просто не хотите, чтобы функция, которую он настраивает, пустым является хорошим показателем этого.
Проблема использования нулевого значения для представления особых случаев заключается в том, что существует только одно нулевое значение и может быть несколько особых случаев. В этом случае я бы передал перечисление в качестве дополнительного параметра, который может указывать на особый случай или на обычное использование значения int. (По сути, это то, что Nullable <> делает для вас, хотя он использует логическое значение вместо перечисления и объединяет параметры в единую структуру.)
источник
В этом случае я думаю, что обнуляемый тип имеет смысл.
Нуль означает отсутствие значения. Это отчетливо отличное понятие от числа со значением 0.
Если вы хотите сказать «Если я не даю вам значение, используйте максимум», тогда передача значения null - это правильный способ выразить это.
источник
Нуль: общее значение ошибки, неопределенное, недействительное или отсутствие значения.
Ноль: фактическое, но не обязательно логическое или интуитивное значение (в этом контексте). Также распространенное значение при инициализации.
В контексте вашей проблемы,
timeoutInMilliseconds
свойство является необязательным, и нет никаких упоминаний о том, что накладные расходы этого подхода могут лишить его права выбора.Вывод: существуют исключения, и решения различаются в зависимости от языка и области; в этом случае я бы выбрал Null. Где (я полагаю) некоторые люди ошибаются, когда плохо разделяют данные от интерфейса. Они просто ожидают, что любой клиент прочитает документацию (или реализацию), чтобы определить, как эти специальные значения должны использоваться / обрабатываться - особые случаи просачиваются в программу клиента, и это может быть совершенно неясно. Добавив хороший уровень абстракции, использование может быть намного понятнее.
источник
Null хуже в использовании, чем
MagicNumber
. Null представляет идею, выраженную лучше, но она не согласована на разных платформах в том, как она ведет себя, использованиеMagicNumber
всегда работает одинаково, что полезно.в зависимости от используемой среды / языка null может
MagicNumber
всегда ведет себя одинаково.источник
Если вы забудете проверить магическое число (произойдет правильно), то магическое число будет продолжаться некоторое время с бессмысленными данными. Намного лучше иметь ноль, который вызывает исключение как можно скорее.
источник
Нуль не единственная альтернатива магическому числу.
Ноль это зло. В приведенном выше примере вы можете обойтись без него, поскольку код, очевидно, сможет обрабатывать нуль. Но в целом, когда вы начинаете передавать нули, рано или поздно вы получите исключение нулевого указателя. Это может не произойти, когда вы впервые пишете код, но он поддерживается гораздо дольше, чем первый выпуск. Его часто поддерживают люди, которые не знают столько о системе, сколько первоначальные разработчики.
У Scala (например) есть хорошая альтернатива в классе Option. Класс Option имеет одно из двух значений: Some - которое оборачивает значение, которое вы действительно хотите, и None - которое не имеет значения.
Это делает очевидным для любого разработчика, что не может быть ценности, и у вас был лучший код для этого. Ну, в любом случае, это должно быть очевидно.
И не все магические числа являются проблемой. В зависимости от контекста 0, 1, 1024 и т. Д. Все может быть очевидным. 347? Да, этого вам следует избегать. :-)
источник