C# Generics Nullable Types


A nullable type can represent the correct range of values for its underlying value type, plus an additional null value. For example, a Nullable<Int32>, pronounced “Nullable of Int32,” can be assigned any value from -2147483648 to 2147483647, or it can be assigned the null value. A Nullable<bool> can be assigned the values true, false, or null.

We have a post called C# Introduction.

Strings are nullable types. Integers are not nullable types. We can make an integer nullable with “?”. The following code will compile and run but at the console there will be no values displayed for the string and the integer.

Nullable types represent value-type variables that can be assigned the value of null. You cannot create a nullable type based on a reference type. Reference types already support the null value. The DateTime struct itself does not provide a null option. But the “DateTime?” nullable type allows you to assign the null literal to the DateTime type.

Reference types are already nullable. You don’t need to use “?” to make them nullable. All strings and classes are reference types. Value types always contain a value but reference types can be null. Reference types hold a reference (pointer) to somewhere else in memory, called the heap, where the actual content is stored.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Nullable
{
    class Program
    {
        static void Main(string[] args)
        {
            string myString = null;  // strings are nullable types so this is okay
            int? myInt = null;   // int is non-nullable type but the ? makes it nullable
            
            if (myInt.HasValue) { ... }

            //int myInt2 = null;
            // ERROR! Cannot convert null to int because it is a non-nullable value type
            
            Console.WriteLine("String is: " + myString);
            Console.WriteLine("Integer is: " + myInt);

            int mySecondInt;
            //Console.WriteLine(mySecondInt);      ERROR! Use of unassigned local variable. Will not compile!

            string mySecondString;
            // Console.WriteLine(mySecondString);  ERROR! Use of unassigned local variable. Will not compile!

            Console.ReadKey();
        }
    }
}

Here is another example.

Generics—Nullable Types
static void Main(string[] args)
{
    System.Nullable<int> nullableInt;
    nullableInt = null;
    if (nullableInt == null) { WriteLine("nullableInt is null"); }
    else { WriteLine("nullableInt is not null"); }
    if (nullableInt.HasValue) { WriteLine("nullableInt is not null"); }
    else { WriteLine("nullableInt is null"); }
    nullableInt = 4;
    if (nullableInt == null) { WriteLine("nullableInt is null"); }
    else { WriteLine("nullableInt is not null"); }
    if (nullableInt.HasValue) { WriteLine("nullableInt is not null"); }
    else { WriteLine("nullableInt is null"); }
    // int? nullableInt is shorthand for System.Nullable<int>
    int? nullableInt2 = 8;
    nullableInt2 = 5;
    ReadKey();
}