#1,199 – Equality and Inequality with Nullable Types

The equality and inequality operators work with nullable types as follows:

  • If both operands are non-null, the operators are applied to the values
  • If one operand is null and the other has a value, == returns false, != returns true
  • If both operands are null, == returns true and != returns false
            int? val1 = 5;
            int? val2 = 10;
            int? val3 = null;
            int? val4 = null;
            int? val5 = 10;

            bool b1 = val1 == val2;   // False
            b1 = val2 == val5;        // True
            b1 = val1 == val3;        // False
            b1 = val1 != val3;        // True
            b1 = val3 == val4;        // True
            b1 = val3 != val4;        // False

#1,198 – Using Operators with Nullable Types

When using a nullable type, you can use the operators with the nullable type that are associated with the underlying value type.

The example below shows how we can use the < and > operators with the int? type.  They work as they would work with the int type itself, for non-null values.

            int? val1 = 5;
            int? val2 = 10;

            bool b1 = val1 < val2;   // True

If one of the two values is null, the expression will evaluate to false, regardless of the other value.

            val2 = null;
            b1 = val1 < val2;    // False
            b1 = val2 < val1;    // False
            b1 = val1 == val2;   // False

#776 – Declaring and Using Nullable structs

You can make any value type nullable, allowing it to either be null or to contain one of its normal values.

Since user-defined structs are value types, you can also make any struct nullable, using Nullable<T> or T? notation.

            // Regular struct
            GuyInfo gi1 = new GuyInfo("Isaac", 1642);

            // Nullable, with no value
            Nullable<GuyInfo> gi2 = null;

            // Nullable, 2nd form, with value
            GuyInfo? gi3 = new GuyInfo("Albert", 1879);

            bool hasVal1 = gi2.HasValue;
            bool hasVal2 = gi3.HasValue;


#582 – Use the as Operator to Unbox to a Nullable Type

You can box regular value types or their equivalent nullable types (e.g. int and int?) and the boxed values will either be null or be of the underlying value type.

You can unbox these values to a nullable type, or use the as operator to do the unboxing.  The example below shows the result of unboxing several different values to a nullable int (int?) using the as operator.

int? i1 = null;   // Nullable<int> w/no value
int? i2 = 42;     // Nullable<int> with a value
int i3 = 12;      // Plain old int

// Boxing nullable types
object o1 = i1;
object o2 = i2;
object o3 = i3;
object o4 = new Dog("I'm not an int", 12);

// Unboxing to nullable types
int? ia1 = o1 as int?;    // null
int? ia2 = o2 as int?;    // 42
int? ia3 = o3 as int?;    // 12
int? ia4 = o4 as int?;    // null

bool bHasVal = ia1.HasValue;  // false
bHasVal = ia2.HasValue;       // true
bHasVal = ia3.HasValue;       // true
bHasVal = ia4.HasValue;       // false

#217 – T? Is Equivalent to Nullable<T>

You can always use the form T?, rather than Nullable<T>, to declare a variable whose type is a nullable value type.  The type T can be any built-in or custom value type.

This means that you can use this syntax for your own custom enum or struct types.

For example, if you have the following custom types:

        public enum Mood

        public struct Point3D
            public float X, Y, Z;
            public string Name;
            public Point3D(float x, float y, float z, string name)
                X = x;
                Y = y;
                Z = z;
                Name = name;

You can use the T? format as follows:

            Mood? myMood = null;
            Mood mood2 = myMood ?? Mood.Elated;

            Point3D? somePoint = null;
            Point3D defaultPoint = new Point3D(0.0f, 0.0f, 0.0f, "Origin");
            Point3D aPoint = somePoint ?? defaultPoint;

#216 – Null-Coalescing (??) Operator Is Equivalent to GetValueOrDefault Method

The Nullable<T> type has a GetValueOrDefault(T) method that behaves in a way identical to the ?? operator.  It returns the value of the object, if non-null, or the value of the parameter passed in if the object is null.

            Nullable<Mood> myMood = null;

            Mood mood2 = myMood ?? Mood.Happy;   // result = Happy, since myMood is null
            Mood mood3 = myMood.GetValueOrDefault(Mood.Happy);   // same as above

There is also an overload of the GetValueOrDefault method that doesn’t take a parameter but just returns the default value for the type T, if the object in question is null.  For example, an enum type has a default value of 0, so the enumerated constant equivalent to 0 is returned.

        public enum Mood
            Crabby,   // 0-valued
            Nullable<Mood> myMood = null;

            Mood mood2 = myMood.GetValueOrDefault();   // Gets value Mood.Crabby

#215 – Using the Null-Coalescing (??) Operator with Custom Nullable Types

In addition to the built-in nullable types, you can also use the null-coalescing operator on custom nullable types using Nullable<T>.

Here’s an example:

            Nullable<Mood> myMood1 = null;
            Nullable<Mood> myMood2 = Mood.Petulant;

            Mood mood3 = myMood1 ?? Mood.Happy;   // result = Happy
            Mood mood4 = myMood2 ?? Mood.Happy;   // result = Petulant