C-Sharp | Java | Python | Swift | GO | WPF | Ruby | Scala | F# | JavaScript | SQL | PHP | Angular | HTML
Here: We see a null int type, the HasValue and Value properties. We use the nullable type to acquire the value of the instance.
PropertyInfo: The int type is aliased to System.Int32—using "System.Int32?" would work as well.
Using SystemHasValue: This property returns a bool that indicates whether the nullable instance contains a set value.
ReturnValue: If the HasValue property is true, you can access the Value property without an exception.
IfC# program that uses nullable int type
using System;
class Program
{
static void Main()
{
//
// Create a local variable of type nullable integer.
// ... It is initially assigned to null.
// ... The HasValue property is false.
//
int? value = null;
Console.WriteLine(value.HasValue);
//
// Assign the nullable integer to a constant integer.
// ... The HasValue property is now true.
// ... You can access the Value property as well.
//
value = 1;
Console.WriteLine(value.HasValue);
Console.WriteLine(value.Value);
Console.WriteLine(value);
if (value == 1)
{
Console.WriteLine("True");
}
}
}
Output
False
True
1
1
True
Also: The program shows that each "bool?" occupies 2 bytes in memory. It has an extra byte of overhead beyond a regular bool.
BoolInfo: This syntax enables us to represent a null, true and false value in a single variable.
C# program that uses nullable bool
using System;
class Program
{
static void Main()
{
bool? tristate = null;
tristate = true;
tristate = false;
Console.WriteLine(tristate);
long m1 = GC.GetTotalMemory(false);
bool?[] b1 = new bool?[100000];
long m2 = GC.GetTotalMemory(false);
b1[0] = false;
Console.WriteLine("{0} bytes per bool?", (m2 - m1) / 100000);
}
}
Output
False
2 bytes per bool?
Info: The enum can be set to Tristate.Null, Tristate.True and Tristate.False. It works like any other enum.
EnumAnd: Unlike the nullable bool, all 3 values can be represented in one byte of storage.
ByteBenefit: The enum type avoids the overhead associated with wrapping a value type in a generic struct.
Generic Class, MethodC# program that uses Tristate byte enum
using System;
class Program
{
enum Tristate : byte
{
Null = 0,
True = 1,
False = 2
}
static void Main()
{
Tristate tristate = Tristate.Null;
tristate = Tristate.True;
tristate = Tristate.False;
Console.WriteLine(tristate);
long m1 = GC.GetTotalMemory(false);
Tristate[] b1 = new Tristate[100000];
long m2 = GC.GetTotalMemory(false);
b1[0] = Tristate.False;
Console.WriteLine("{0} byte(s) per Tristate", (m2 - m1) / 100000);
}
}
Output
False
1 byte(s) per Tristate
Tip: A "DateTime?" is a struct that wraps a DateTime struct, providing another level of indirection that can simplify some programs.
Main: Here the "DateTime?" variable is declared. It is passed as a parameter to the Test method, and is assigned to different values.
HasValue: This returns true if the nullable type is logically non-null, and false if the null field on the nullable type is activated.
Also: The GetValueOrDefault method will return DateTime.MinValue for a null DateTime.
DateTime.MinValueC# program that uses null DateTime struct
using System;
class Program
{
static void Main()
{
//
// Declare a nullable DateTime instance and assign to null.
// ... Change the DateTime and use the Test method.
//
DateTime? value = null;
Test(value);
value = DateTime.Now;
Test(value);
value = DateTime.Now.AddDays(1);
Test(value);
//
// You can use the GetValueOrDefault method on nulls.
//
value = null;
Console.WriteLine(value.GetValueOrDefault());
}
static void Test(DateTime? value)
{
//
// This method uses the HasValue property.
// ... If there is no value, the number zero is written.
//
if (value.HasValue)
{
Console.WriteLine(value.Value);
}
else
{
Console.WriteLine(0);
}
}
}
Output
0
9/29/2009 9:56:21 AM
9/30/2009 9:56:21 AM
1/1/0001 12:00:00 AM
C# program that uses Nullable generic struct
using System;
class Program
{
static void Main()
{
// Use Nullable directly.
Nullable<int> test = 100;
if (test.HasValue)
{
Console.WriteLine("HAS VALUE: {0}", test.Value);
}
// Set Nullable int to null.
test = null;
if (test.HasValue)
{
Console.WriteLine("NOT REACHED");
}
}
}
Output
HAS VALUE: 100
Here: We measure the memory usage in the managed heap before and after allocating an array of nullable ints.
Tip: The GC.GetTotalMemory method is used to determine the resource usage of the program before and after the allocation occurs.
GC.CollectResult: The nullable type wrapper requires 4 bytes of storage. And the integer itself requires 4 bytes for each element.
Opinion: This is an efficient implementation. In an array many nullable types are stored in contiguous memory.
C# program that computes memory usage for nullables
using System;
class Program
{
static void Main()
{
//
// Compute the memory usage for a nullable type integer.
// ... The program allocates one million nullable int structs.
//
const int size = 1000000;
long b1 = GC.GetTotalMemory(true);
int?[] array1 = new int?[size];
long b2 = GC.GetTotalMemory(true);
array1[0] = null;
Console.WriteLine((b2 - b1) / (double)size);
}
}
Output
8.000016