В чем разница между null и System.DBNull.Value?

92

Есть ли разница между null и System.DBNull.Value? Если да, то что это?

Я заметил это поведение сейчас -

while (rdr.Read())
{
    if (rdr["Id"] != null) //if (rdr["Id"] != System.DBNull.Value)  
    {
        int x = Convert.ToInt32(rdr["Id"]);
    }
}

Пока я извлекаю данные из базы данных с помощью sql datareader, хотя возвращаемое значение не if(rdr["Id"] != null)возвращается trueи в конечном итоге вызывает исключение для приведения значения null как целого числа.

Но это, если я использую if (rdr["Id"] != System.DBNull.Value)возврат false.

В чем разница между null и System.DBNull.Value?

застеленный
источник
Ну, они не связаны. Один является статическим экземпляром класса в System.Data, а другой - специальным значением, обозначающим отсутствие референта. Они не имеют ничего общего друг с другом. Не могли бы вы пояснить, в чем вы запутались? Ваш настоящий вопрос "зачем делать DataRowsи DataReadersвкладывать DBNull.Valueвнутрь себя, а не null?"
mqp
Ну, изначально это было не так, но, узнав из того, что вы сказали, мне стало любопытно. Не могли бы вы сказать мне, почему DataRows и DataReaders помещают в себя DBNull.Value вместо null?
pavanred
Я сам не уверен. Вот один ответ: stackoverflow.com/questions/4488727/what-is-the-point-of-dbnull/… Также возможно, что до того, как в C # появились типы значений, допускающие значение NULL, с этим было бы сложнее справиться null.
mqp
1
У меня здесь был ответ, но я понял, что он больше подходит для stackoverflow.com/questions/4488727/what-is-the-point-of-dbnull - поэтому я переместил его
Марк Гравелл

Ответы:

118

Ну nullэто не экземпляр какого-либо типа. Скорее, это недействительная ссылка.

Однако System.DbNull.Valueэто действительная ссылка на экземпляр System.DbNull( System.DbNullявляется синглтоном и System.DbNull.Valueдает вам ссылку на единственный экземпляр этого класса), который представляет несуществующие * значения в базе данных.

* Обычно мы говорим null, но я не хочу мешать этому вопросу.

Итак, между ними есть большая концептуальная разница. Ключевое слово nullпредставляет собой недопустимую ссылку. Класс System.DbNullпредставляет несуществующее значение в поле базы данных. В общем, мы должны стараться избегать использования одного и того же (в данном случае null) для представления двух очень разных концепций (в данном случае недопустимая ссылка или несуществующее значение в поле базы данных).

Имейте в виду, вот почему многие люди выступают за использование шаблона нулевого объекта в целом, что и System.DbNullявляется примером.

Джейсон
источник
43
+1 Практический пример: если вы используете IDbCommand.ExecuteScalar(), он может либо вернуть null (записи не возвращаются), либо DbNull(первый столбец в первой записи - «несуществующее значение»). Без DbNullвас было бы невозможно отличить одно от другого.
C.Evenhuis
Я настоятельно рекомендую использовать язык, который запрещает использование Null и делает это абсолютно без дополнительных затрат. жизнь слишком коротка для "шаблона нулевого объекта"
Николас
3
Пустая ссылка вполне допустима. ☺
IllidanS4 поддерживает Монику
@ C.Evenhuis. Есть еще один общий совет: функция должна возвращать только один тип значения. Вот почему люди предпочитают хорошо типизированный код TypeScript. «Каков статус выполнения» отличается от «Каков результат вычислений». Т.е. они могли бы решить реализовать эту функцию как-нибудь иначе (может быть, параметр out или объект, подобный objs ответа HTTP-запроса). Конечно, это нежелательное осложнение, но если бы они это сделали, возможно, вместо DbNull можно было бы использовать null.
klenium
21

Из документации класса DBNull :

Не путайте понятие null в объектно-ориентированном языке программирования с объектом DBNull. В объектно-ориентированном языке программирования null означает отсутствие ссылки на объект. DBNull представляет собой неинициализированный вариант или несуществующий столбец базы данных.

Heinzi
источник
11

DBNull.Value раздражает, когда приходится иметь дело.

Я использую статические методы, которые проверяют, есть ли значение DBNull, а затем возвращают значение.

SqlDataReader r = ...;
String firstName = getString(r[COL_Firstname]);

private static String getString(Object o) {
   if (o == DBNull.Value) return null;
   return (String) o;
}

Кроме того, при вставке значений в DataRow вы не можете использовать «null», вы должны использовать DBNull.Value.

Наличие двух представлений «null» - плохой дизайн без видимой выгоды.

Ненависть
источник
2
Чувство отвращения, которое мы разделяем, re: ваше последнее заявление превосходит только иронию того, что вы пришли сюда, чтобы прочитать это и узнали, что ваше имя пользователя "отвращение"
Iofacture
5

DBNull.Value - это то, что возвращают поставщики баз данных .NET для представления нулевой записи в базе данных. DBNull.Value не равен нулю, и сравнения с нулевым значением для значений столбцов, полученных из строки базы данных, не будут работать, вы всегда должны сравнивать с DBNull.Value.

http://msdn.microsoft.com/en-us/library/system.dbnull.value.aspx

Джеймс Майкл Хэйр
источник
ps Вы также должны использовать DBNull.Value для передачи нулевого параметра в базу данных, иначе это может быть интерпретировано как параметр не был передан.
Джеймс Майкл Хэйр
1
DBNull - это не «то, что возвращает база данных» - это просто то, как ADO.NET решает его интерпретировать; лично я не уверен, что эта интерпретация очень ценна
Марк Грейвелл
@MarcGravell Да, Марк, ты прав. Я сформулировал это неправильно. ASP.NET переводит значение пустого столбца базы данных в DBNull.Value
Джеймс Майкл Хэйр,
3

DataRow имеет метод, который вызывается IsNull(), который можно использовать для проверки столбца, если он имеет нулевое значение - относительно нулевого значения, видимого в базе данных.

DataRow["col"]==nullвсегда будет false.

использовать

DataRow r;
if (r.IsNull("col")) ...

вместо.

Даниэль Мошмондор
источник
3

Null похож на нулевой указатель в C ++ . Так что это ссылка, которая не указывает ни на какое значение .

DBNull.Valueполностью отличается и является константой, которая возвращается, когда значение поля содержит NULL.

Алиостад
источник