Recipe 4.7. Creating a Value Type That Can Be Initialized to NullProblemYou have a variable that is a numeric type, which will hold a numeric value obtained from a database. The database may return this value as a null. You need a simple clean way to store this numeric value, even if it is returned as a null. SolutionUse a nullable value type. There are two ways of creating a nullable value type. The first way is to use the ? type modifier: int? myDBInt = null; The second way is to use the Nullable<T> generic type: Nullable<int> myDBInt = new Nullable<int>(); DiscussionEssentially both of the following statements are equivalent: int? myDBInt = null; Nullable<int> myDBInt = new Nullable<int>(); In both cases, myDBInt is considered a nullable type and is initialized to null. A nullable type implements the INullableValue interface, which has two read-only property members, HasValue and Value. The HasValue property returns false if the nullable type is set to null; otherwise it returns true. If HasValue returns TRue, you can access the Value property, which contains the currently stored value in the nullable data type. If HasValue returns false and you attempt to read the Value property, you will get an InvalidOperationException tHRown. This is because the Value property is undefined at this point. In addition, testing the nullable type can be done in one of two ways. First, by using the HasValue property as shown here: if (myDBInt.HasValue) Console.WriteLine("Has a value: " + myDBInt.Value); else Console.WriteLine("Does not have a value (NULL)"); and, second, by comparing it to null: if (myDBInt != null) Console.WriteLine("Has a value: " + myDBInt.Value); else Console.WriteLine("Does not have a value (NULL)"); Either method is acceptable. When casting a nullable type to a non-nullable type, the cast operates as it would normally, except when the nullable type is set to null. In this case, an InvalidOperationException is thrown. When casting a non-nullable type to a nullable type, the cast operates as it would normally. No InvalidOperationException will be thrown, as the non-nullable type can never be null. The tricky thing to watch out for with nullable types is when comparisons are performed. For example if the following code is executed: if (myTempDBInt < 100) Console.WriteLine("myTempDBInt < 100"); else Console.WriteLine("myTempDBInt >= 100"); The text "myTempDBInt >= 100" is displayed, which is obviously incorrect. To fix this code, you have to check if myTempDBInt is null. If it is not, you can execute the if statement in the previous code block: if (myTempDBInt != null) { if (myTempDBInt < 100) Console.WriteLine("myTempDBInt < 100"); else Console.WriteLine("myTempDBInt >= 100"); } else { // Handle the null here. } Another interesting thing about nullable types is that you can use them in expressions similar to normal numeric types, for example: int? DBInt = 10; int Value = 2; int? Result = DBInt + Value; // Result == 12 The result of using a nullable type in an expression is a null if any nullable type is null. However, if none of the nullable types is null, the operation is evaluated as it normally would be. If DBInt, for example, is set to null, the value placed in Result will also be null. See AlsoSee the "Nullable<T> Generic Class" and "Using Nullable Types" topics in the MSDN documentation. |