What is the difference between null and System.DBNull.Value? - c#

Is there any difference between null and System.DBNull.Value? If yes, what is it?
I noticed this behavior now -
while (rdr.Read())
{
if (rdr["Id"] != null) //if (rdr["Id"] != System.DBNull.Value)
{
int x = Convert.ToInt32(rdr["Id"]);
}
}
While I retrieve data from the database using a sql datareader, though there is no value returned if(rdr["Id"] != null) returned true and eventually threw an exception for casting a null as integer.
But, this if I use if (rdr["Id"] != System.DBNull.Value) returns false.
What's the difference between null and System.DBNull.Value?

Well, null is not an instance of any type. Rather, it is an invalid reference.
However, System.DbNull.Value, is a valid reference to an instance of System.DbNull (System.DbNull is a singleton and System.DbNull.Value gives you a reference to the single instance of that class) that represents nonexistent* values in the database.
*We would normally say null, but I don't want to confound the issue.
So, there's a big conceptual difference between the two. The keyword null represents an invalid reference. The class System.DbNull represents a nonexistent value in a database field. In general, we should try avoid using the same thing (in this case null) to represent two very different concepts (in this case an invalid reference versus a nonexistent value in a database field).
Keep in mind, this is why a lot of people advocate using the null object pattern in general, which is exactly what System.DbNull is an example of.

From the documentation of the DBNull class:
Do not confuse the notion of null in an object-oriented programming language with a DBNull object. In an object-oriented programming language, null means the absence of a reference to an object. DBNull represents an uninitialized variant or nonexistent database column.

DBNull.Value is annoying to have to deal with.
I use static methods that check if it's DBNull and then return the value.
SqlDataReader r = ...;
String firstName = getString(r[COL_Firstname]);
private static String getString(Object o) {
if (o == DBNull.Value) return null;
return (String) o;
}
Also, when inserting values into a DataRow, you can't use "null", you have to use DBNull.Value.
Have two representations of "null" is a bad design for no apparent benefit.

DBNull.Value is what the .NET Database providers return to represent a null entry in the database. DBNull.Value is not null and comparissons to null for column values retrieved from a database row will not work, you should always compare to DBNull.Value.
http://msdn.microsoft.com/en-us/library/system.dbnull.value.aspx

DataRow has a method that is called IsNull() that you can use to test the column if it has a null value - regarding to the null as it's seen by the database.
DataRow["col"]==null will allways be false.
use
DataRow r;
if (r.IsNull("col")) ...
instead.

Null is similar to zero pointer in C++. So it is a reference which not pointing to any value.
DBNull.Value is completely different and is a constant which is returned when a field value contains NULL.

Related

Why do I get a null reference error when using something.Equals(null) in C#

I keep getting a null reference error when I am trying to check if something is null. I have a class called User and I initialize the variable indvUser like so
User indvUser = api.Users.SearchByExternalId(session.UserInfo.UserId.ToString())
.Users.FirstOrDefault();
Then I want to check if indvUser is null like this
if (indvUser.Equals(null))
{
int a = 1;
}
But I get a null reference error when using Equals(null) which I don't understand. If it actually is null i.e. there is no value, shouldn't Equals(null) return true?
Since indvUser is null, and indvUser.Equals is an instance method on your User object (i.e., it requires an non-null instance of your object), .NET will throw the error you attempt to use it.
For something like this, you could use this:
Object.ReferenceEquals(indvUser, null)
Or simply:
indvUser == null
Since neither of these approaches actually attempt to access methods or properties on the indvUser object itself, you should be safe from NullReferenceExceptions
In line:
indvUser.Equals(null)
if indvUser is null, how Equals method could be called on it? It simply can be seen as:
null.Equals(null)
You should compare it as indvUser == null or object.ReferenceEquals(indvUser, null)
Object.Equals is a method which is not static. In order to call the Equals method, you must have an instance of the class.
If indUser == null you'd be doing null.Equals(null) which would throw an exception.

linq-to-sql SingleOrDefault return when null

I'm writing a linq-to-sql query and I'm loading an ID (a bigint in the database and a long in my code) from a table, something like this:
var SomeQuery = (from x in ...
select x.ID).SingleOrDefault();
When I get the result, I use SingleOrDefault in case the return is empty. Does that mean that if the result is empty the SomeQuery variable will be 0 or null?
Thanks.
If you look the documenation for SingleOrDefault
Returns the only element of a sequence, or a default value if the
sequence is empty; this method throws an exception if there is more
than one element in the sequence.
It cleary states that if the sequence is empty it will return the default value which for long and bigint is 0. Why explained below
Documenation for default keyword states
In generic classes and methods, one issue that arises is how to assign
a default value to a parameterized type T when you do not know the
following in advance:
Whether T will be a reference type or a value type.
If T is a value type, whether it will be a numeric value or a struct.
Given a variable t of a parameterized type T, the statement t = null
is only valid if T is a reference type and t = 0 will only work for
numeric value types but not for structs. The solution is to use the
default keyword, which will return null for reference types and zero
for numeric value types.
Default is returned if no element found.(default value of int is 0)
Value is returned if one is found.
Exception is thrown if more than one is found.

C# null - is it an object

When I was writing C# code a few days ago I noticed that the compiler complained that I had to cast null to a specific object.
Does this mean that null is simply an uninstantiated version of the type? Or is it a singleton value of a Null class like Java (even though it has special privileges)?
EDIT: an example of the code giving the error would be:
public String duplicate(String toDuplicate)
{
return toDuplicate + toDuplicate;
}
public String duplicate(int? toDuplicate)
{
String asString = toDuplicate.toString();
return asString + asString;
}
public static int Main(string[] args)
{
//This needs to be cast:
duplicate(null);
//To:
duplicate((string)null);
}
The reason I commented on null in Java was after reading this:
There is also a special null type, the
type of the expression null, which has
no name. Because the null type has no
name, it is impossible to declare a
variable of the null type or to cast
to the null type. The null reference
is the only possible value of an
expression of null type. The null
reference can always be cast to any
reference type. In practice, the
programmer can ignore the null type
and just pretend that null is merely a
special literal that can be of any
reference type.
Found here: Is null an Object?
I get the error you refer when i have overloaded methods and the compiler can't resolve which method to call at compile time. Is that it?
According to the MSDN description:
The null keyword is a literal that represents a null reference, one that does not refer to any object. null is the default value of reference-type variables. Ordinary value types cannot be null. However, C# 2.0 introduced nullable value types.
null is the "uninstanciated reference" for any type. It is not a value. null has no defined type.
No - the null is just a literal for the null reference.
The reason you need to "cast" it in this way (I put the word cast in quotes because you are not really casting an instance of anything), is purely to help the compiler resolve which overload of a method you are calling, or the method you are calling even exists.
In your example, you need to specify that you are calling the method "duplicate" that takes a single string argument. If you omit the cast, then the compiler only knows that the method you intended to call is called "duplicate" and has a single argument, but can't tell what type the argument is - did you mean to call duplicate(string) or did you mean to call duplicate(some other type)? Should it compile, or should it error telling you the method you are trying to call does not exist?
You will also get the same issue if you had a duplicate(byte[]) defined, because now your call is ambiguous without the explicit cast.
No its not an object. null is the default value of reference-type variables. Ordinary value types cannot be null. but there is another set called nullable types.
You are probably referring to the fact that the following leads to a compiler error:
int? nullableInt = (somecondition) ? value : null;
Indeed you need to add a cast here:
int? nullableInt = (somecondition) ? value : (int?)null;
Even though I'm not able to explain this in detail, I'd suspect the following:
int? is actually a short form for Nullable<int>, so it is basically an object instance. When assigning an int value to nullableInt, a property of Nullable<int> will be set internally. Directly assigning null would also be ok.
The conditional assignment however, would return two different types: int in case somecondition is true and object (null) otherwise.
Now the compiler doesn't know how to handle this, as the ternary operator needs to return values of the same type. So you need to specify the desired "type for the null value".
Sorry if this is not a very deep technical explanation - I'm sure there's somebody who can elaborate this better, but it might help understand this better.

Why couldn't I check for a null reference on a connection string?

Probably a C# noob question, so don't flame me. I was trying to do this:
if (ConfigurationManager.ConnectionStrings["PrimaryConnectionString"].ConnectionString != null)
{
// ...
}
But I kept getting a System.NullReferenceException. I thought since it returns a string that I could just check for null and move on. It took me a while to find the right way to do it:
ConnectionStringSettings cs = ConfigurationManager.ConnectionStrings["PrimaryConnectionString"];
if (cs != null)
{
this.Connection.ConnectionString = cs.ConnectionString;
}
So in other instances, like checking a Session object for some value I would do a check for null like this:
if (Session["EmployeeID"] != null)
{
_EmployeeID = System.Convert.ToInt32(Session["EmployeeID"]);
}
So I just wanted to know how do you know when you can or can't do a check for null?
Your problem was that you were checking:
ConfigurationManager
.ConnectionStrings["PrimaryConnectionString"]
.ConnectionString
for a null pointer.
In actual fact,
ConfigurationManager
.ConnectionStrings["PrimaryConnectionString"]
was null so that, when you tried to dereference that to get the connection string, that's when you got the exception. Effectively, what you're doing is:
null.ConnectionString
which is problematic.
I tend to either avoid many layers of dereferencing in a single statement or place an exception handler around the whole thing to catch problems at any point.
Your null reference exception happened in parent object (ConfigurationManager.ConnectionStrings["PrimaryConnectionString"]). Once you check it also, you are fine.
try this:
if ((ConfigurationManager.ConnectionStrings["PrimaryConnectionString"] != null)
&& (ConfigurationManager.ConnectionStrings["PrimaryConnectionString"].ConnectionString != null))
{ etc etc }
Notice that if you use more methods from it, it would be useful to separate these checks.
Your first test checks whether the connection string within the ConnectionStringSettings is null. The second test checks whether the ConnectionStringSettings reference itself is null. It's the difference between:
if (person.Name == null)
and
if (person == null)
The first will go bang if person is null; the second won't spot if person.Name is null. If you want to check both, you need:
if (person == null || person.Name == null)
Some languages (such as Groovy) have a null-safe dereferencing operator, so you can do:
var x = Expr1?.Expr2?.Expr3?.Expr4;
That makes this sort of test easier, if you want to test whether any part of a potentially long expression is null. Unfortunately C# doesn't have that :(
So I just wanted to know how do you
know when you can or can't do check
for null?
You can check for null at any time you like (except with non-nullable value types, that cannot be null).
You should check for null at any time you wish to access the members of an object, and you are not certain that the variable containing the object is not null.
A couple of typical places for null check are:
You get an object passed to you as a parameters in a function you are writing. Do a null-check on the parameter before using it.
You call a method (or fetch a property value) returning an object that you wish to use. Do a null-check on that return value before using it.
You pass an object to a method where it is documented that it will throw a NullReferenceException if the parameter is null. Do a null check on the variable you wish to pass before calling the method.

What is the best way to deal with DBNull's

I frequently have problems dealing with DataRows returned from SqlDataAdapters. When I try to fill in an object using code like this:
DataRow row = ds.Tables[0].Rows[0];
string value = (string)row;
What is the best way to deal with DBNull's in this type of situation.
Nullable types are good, but only for types that are not nullable to begin with.
To make a type "nullable" append a question mark to the type, for example:
int? value = 5;
I would also recommend using the "as" keyword instead of casting. You can only use the "as" keyword on nullable types, so make sure you're casting things that are already nullable (like strings) or you use nullable types as mentioned above. The reasoning for this is
If a type is nullable, the "as" keyword returns null if a value is DBNull.
It's ever-so-slightly faster than casting though only in certain cases. This on its own is never a good enough reason to use as, but coupled with the reason above it's useful.
I'd recommend doing something like this
DataRow row = ds.Tables[0].Rows[0];
string value = row as string;
In the case above, if row comes back as DBNull, then value will become null instead of throwing an exception. Be aware that if your DB query changes the columns/types being returned, using as will cause your code to silently fail and make values simple null instead of throwing the appropriate exception when incorrect data is returned so it is recommended that you have tests in place to validate your queries in other ways to ensure data integrity as your codebase evolves.
If you aren't using nullable types, the best thing to do is check to see if the column's value is DBNull. If it is DBNull, then set your reference to what you use for null/empty for the corresponding datatype.
DataRow row = ds.Tables[0].Rows[0];
string value;
if (row["fooColumn"] == DBNull.Value)
{
value = string.Empty;
}
else
{
value = Convert.ToString(row["fooColumn"]);
}
As Manu said, you can create a convert class with an overloaded convert method per type so you don't have to pepper your code with if/else blocks.
I will however stress that nullable types is the better route to go if you can use them. The reasoning is that with non-nullable types, you are going to have to resort to "magic numbers" to represent null. For example, if you are mapping a column to an int variable, how are you going to represent DBNull? Often you can't use 0 because 0 has a valid meaning in most programs. Often I see people map DBNull to int.MinValue, but that could potentially be problematic too. My best advice is this:
For columns that can be null in the database, use nullable types.
For columns that cannot be null in the database, use regular types.
Nullable types were made to solve this problem. That being said, if you are on an older version of the framework or work for someone who doesn't grok nullable types, the code example will do the trick.
Add a reference to System.Data.DataSetExtensions, that adds Linq support for querying data tables.
This would be something like:
string value = (
from row in ds.Tables[0].Rows
select row.Field<string>(0) ).FirstOrDefault();
I always found it clear, concise, and problem free using a version of the If/Else check, only with the ternary operator. Keeps everything on one row, including assigning a default value if the column is null.
So, assuming a nullable Int32 column named "MyCol", where we want to return -99 if the column is null, but return the integer value if the column is not null:
return row["MyCol"] == DBNull.Value ? -99 : Convert.ToInt32(Row["MyCol"]);
It is the same method as the If/Else winner above - But I've found if you're reading multiple columns in from a datareader, it's a real bonus having all the column-read lines one under another, lined up, as it's easier to spot errors:
Object.ID = DataReader["ID"] == DBNull.Value ? -99 : Convert.ToInt32(DataReader["ID"]);
Object.Name = DataReader["Name"] == DBNull.Value ? "None" : Convert.ToString(DataReader["Name"]);
Object.Price = DataReader["Price"] == DBNull.Value ? 0.0 : Convert.ToFloat(DataReader["Price"]);
If you have control of the query that is returning the results, you can use ISNULL() to return non-null values like this:
SELECT
ISNULL(name,'') AS name
,ISNULL(age, 0) AS age
FROM
names
If your situation can tolerate these magic values to substitute for NULL, taking this approach can fix the issue through your entire app without cluttering your code.
DBNull implements .ToString() like everything else. No need to do anything. Instead of the hard cast, call the object's .ToString() method.
DataRow row = ds.Tables[0].Rows[0];
string value;
if (row["fooColumn"] == DBNull.Value)
{
value = string.Empty;
}
else
{
value = Convert.ToString(row["fooColumn"]);
}
this becomes:
DataRow row = ds.Tables[0].Rows[0];
string value = row.ToString()
DBNull.ToString() returns string.Empty
I would imagine this is the best practice you're looking for
It is worth mentioning, that DBNull.Value.ToString() equals String.Empty
You can use this to your advantage:
DataRow row = ds.Tables[0].Rows[0];
string value = row["name"].ToString();
However, that only works for Strings, for everything else I would use the linq way or a extension method. For myself, I have written a little extension method that checks for DBNull and even does the casting via Convert.ChangeType(...)
int value = row.GetValueOrDefault<int>("count");
int value = row.GetValueOrDefault<int>("count", 15);
Often when working with DataTables you have to deal with this cases, where the row field can be either null or DBNull, normally I deal with that like this:
string myValue = (myDataTable.Rows[i]["MyDbNullableField"] as string) ?? string.Empty;
The 'as' operator returns null for invalid cast's, like DBNull to string, and the '??' returns
the term to the right of the expression if the first is null.
You can also test with Convert.IsDBNull (MSDN).
I usually write my own ConvertDBNull class that wraps the built-in Convert class. If the value is DBNull it will return null if its a reference type or the default value if its a value type.
Example:
- ConvertDBNull.ToInt64(object obj) returns Convert.ToInt64(obj) unless obj is DBNull in which case it will return 0.
For some reason I've had problems with doing a check against DBNull.Value, so I've done things slightly different and leveraged a property within the DataRow object:
if (row.IsNull["fooColumn"])
{
value = string.Empty();
}
{
else
{
value = row["fooColumn"].ToString;
}
Brad Abrams posted something related just a couple of days ago
http://blogs.msdn.com/brada/archive/2009/02/09/framework-design-guidelines-system-dbnull.aspx
In Summary "AVOID using System.DBNull. Prefer Nullable instead."
And here is my two cents (of untested code :) )
// Or if (row["fooColumn"] == DBNull.Value)
if (row.IsNull["fooColumn"])
{
// use a null for strings and a Nullable for value types
// if it is a value type and null is invalid throw a
// InvalidOperationException here with some descriptive text.
// or dont check for null at all and let the cast exception below bubble
value = null;
}
else
{
// do a direct cast here. dont use "as", "convert", "parse" or "tostring"
// as all of these will swallow the case where is the incorect type.
// (Unless it is a string in the DB and really do want to convert it)
value = (string)row["fooColumn"];
}
And one question... Any reason you are not using an ORM?
You should also look at the extension methods. Here are some examples to deal with this scenerio.
Recommended read
If you are concerned with getting DBNull when expecting strings, one option is to convert all the DBNull values in the DataTable into empty string.
It is quite simple to do it but it would add some overhead especially if you are dealing with large DataTables. Check this link that shows how to do it if you are interested

Categories

Resources