У чому різниця між 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, хоча повернене значення не if(rdr["Id"] != null)повертається trueі врешті-решт викидає виняток для лиття нуля як цілого числа.

Але це, якщо я використовую if (rdr["Id"] != System.DBNull.Value)return false.

У чому різниця між null і System.DBNull.Value?


Ну, вони не пов’язані між собою. Один є статичним екземпляром класу в System.Data, а інший - особливим значенням, що означає відсутність референта. Вони не мають нічого спільного між собою. Чи можете ви детальніше розповісти, що вас бентежить? Ваше справжнє запитання "навіщо робити DataRowsі DataReadersвкладати DBNull.Valueвсередину себе, а не null?"
mqp

Ну, спочатку це було не так, але після вивчення того, що ви сказали, мені цікаво. Не могли б ви сказати мені, чому DataRows і DataReaders розміщують DBNull.Value в собі замість null?
пройшов параван

Я сам не впевнений. Ось одна відповідь: stackoverflow.com/questions/4488727/what-is-the-point-of-dbnull/ ... Також можливо, що до того, як типи значень, що допускають обнулення, були в C #, це мало б бути клопотом null.
mqp

1
У мене була відповідь тут, але я зрозумів, що вона більше підходить для stackoverflow.com/questions/4488727/what-is-the-point-of-dbnull - тож я її перемістив
Marc Gravell

Відповіді:


117

Ну, 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 або об'єкт, подібний до відповіді на запит HTTP objs). Звичайно, це не дуже бажане ускладнення, але якби вони це зробили, можливо, замість DbNull можна було б використовувати null.
klenium

21

З документації класу DBNull :

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


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.

Мати два подання "нуль" - це поганий дизайн без очевидної вигоди.


2
Почуття огиди, з яким ми поділяємось, повторюється: ваше останнє твердження виправдане лише іронією показатись тут, щоб прочитати це, і з'ясувати, що ваше ім'я користувача "огида"
Іофактура,

5

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

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


ps Ви також повинні використовувати DBNull.Value для передачі нульового параметра в базу даних, інакше він може бути інтерпретований як параметр не переданий.
James Michael Hare

1
DBNull - це не "те, що повертає база даних" - це просто те, як ADO.NET вирішує її інтерпретувати; особисто я не впевнений, що таке тлумачення є дуже цінним
Марк Гравелл

@MarcGravell Так, Марк, ти маєш рацію. Я сформулював це неправильно. ASP.NET переводить значення нульового стовпця бази даних у DBNull.Value
James Michael Hare

3

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

DataRow["col"]==nullзавжди буде false.

використання

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

замість цього.


3

Null подібний до нульового покажчика в C ++ . Тож це посилання, яке не вказує на якесь значення .

DBNull.Valueабсолютно інший і є константою, яка повертається, коли значення поля містить NULL.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.