Я собираюсь не согласиться с трендом здесь. Я пойду на запись:
Я не согласен с тем, что DBNull
служит какой-либо полезной цели; это добавляет ненужную путаницу, хотя и не вносит никакой пользы.
Часто выдвигается аргумент, что null
- недопустимая ссылка, а DBNull
- шаблон нулевого объекта; ни то, ни другое . Например:
int? x = null;
это не "недействительная ссылка"; это null
значение. Действительно, null
означает, что вы хотите, чтобы это значило, и, честно говоря, у меня нет абсолютно никаких проблем с работой со значениями, которые могут быть null
(действительно, даже в SQL нам нужно правильно работать с null
- здесь ничего не меняется). Точно так же «шаблон нулевого объекта» имеет смысл, только если вы фактически рассматриваете его как объект в терминах ООП, но если у нас есть значение, которое может быть «нашим значением или DBNull
», тогда оно должно быть object
поэтому мы не можем ничего с этим сделать полезного.
Есть так много плохих вещей с DBNull
:
- заставляет работать с
object
, поскольку только object
может содержать DBNull
или другое значение
- нет реальной разницы между "может быть значением" или
DBNull
"против" может быть значением или null
"
- аргумент, что это происходит из 1.1 (pre-nullable-types), не имеет смысла; мы могли бы прекрасно использовать
null
в 1.1
- У большинства API есть "это ноль?" методы, например
DBDataReader.IsDBNull
или DataRow.IsNull
- ни один из которых на самом деле не требует DBNull
существования в терминах API
DBNull
терпит неудачу с точки зрения объединения нулей; value ?? defaultValue
не работает, если значение DBNull
DBNull.Value
нельзя использовать в необязательных параметрах, поскольку он не является константой
- семантика времени выполнения
DBNull
идентична семантике null
; в частности, DBNull
фактически равняется DBNull
- так что не не выполняет работу по представлению семантики SQL
- это часто вынуждает упаковывать значения типа значения, так как он чрезмерно использует
object
- если вам нужно проверить на
DBNull
, вы могли бы также проверить на null
- это вызывает огромные проблемы для таких вещей, как параметры команды, с очень глупым поведением, что если параметр имеет значение
null
, он не отправляется ... ну, вот идея: если вы не хотите отправленный параметр - не добавлять его в коллекцию параметров
- каждый ORM, который я могу придумать, прекрасно работает без любой необходимости или использования
DBNull
, за исключением случаев, когда возникает дополнительная неприятность при разговоре с кодом ADO.NET
Единственный даже удаленно убедительный аргумент, который я когда-либо видел, чтобы оправдать существование такого значения, находится в DataTable
при передаче значений создать новую строку; null
означает «использовать значение по умолчанию», DBNull
явно равен нулю - честно говоря, этот API мог бы иметь конкретную обработку для этого случая - например, воображаемый DataRow.DefaultValue
был бы намного лучше, чем введение DBNull.Value
без какой-либо причины заражает обширные участки кода.
Точно так же сценарий ExecuteScalar
... в лучшем случае незначителен; если вы выполняете скалярный метод, вы ожидаете результата. В сценарии, где нет строк, возврат null
не кажется слишком ужасным. Если вам абсолютно необходимо устранить неоднозначность между «без строк» и «возвращен один ноль», есть API для чтения.
Этот корабль давно отплыл, и уже слишком поздно его чинить. Но! Пожалуйста, сделайте не и подумайте, что все согласны с тем, что это "очевидная" вещь. Многие разработчики не видят значение в этой странной складке на BCL.
Мне действительно интересно, все ли это проистекает из двух вещей:
- необходимость использовать слово
Nothing
вместо чего-то, включающего "ноль" в VB
- имея возможность использовать синтаксис
if(value is DBNull)
, который "выглядит как SQL", а не как о-о-хитро if(value==null)
Резюме:
Наличие 3-х опций (null
, DBNull
или фактическое значение) полезно только в том случае, если есть подлинный пример, в котором вам необходимо устранить неоднозначность между 3 разными случаями.Я еще не видел случая, когда мне нужно было бы представлять два разных «нулевых» состояния, поэтому DBNull
полностью избыточен, поскольку null
уже существует и имеет гораздо лучшую поддержку языка и среды выполнения.