Nullable types in C# are an extension of value types that allows them to contain the value null
(in addition to their normal values). This is useful in scenarios where a value may be optional or not always available.
In C#, the value null
is used to represent an absence of value. However, value types (like int
, double
, bool
) cannot be null
by default; they always have a default value.
To address this limitation, nullable types are introduced, which allow value types to have the value null
.
Declaration and Use of Nullable Types
To declare a nullable type, the ?
operator is used after the value type. For example, int?
is a nullable type that can contain an integer or null
.
The syntax for declaring a nullable type is simple. For example,
int? age = null;
double? salary = 4500.50;
bool? isActive = null;
Here, number
is a variable that can hold an integer or the value null
.
Nullable Types and the Nullable<T>
Structure
Under the hood, the above syntax uses the generic Nullable<T>
structure. For example:
Nullable<int> myNumber = null;
Both forms (Nullable<T>
and T?
) are equivalent, but using the ?
operator is more common and easier to read.
Nullity Check
To check if a nullable type has a value or is null, you can use the HasValue
and Value
properties. The HasValue
property indicates whether the nullable type contains a value:
if (age.HasValue)
{
Console.WriteLine($"The age is {age.Value}");
}
else
{
Console.WriteLine("The age is not assigned.");
}
Default Value Assignment
The null-coalescing operator ??
provides a compact way to handle nullable values, allowing you to define a default value in case the nullable is null
.
int? number = null;
int result = number ?? 5;
Console.WriteLine(result); // Prints 5
In this case, if number
is null
, result
will take the value 5. If number
has a value, result
will be equal to number
.
Conversion Between Nullable and Non-nullable Types
If you need to convert a nullable type to a non-nullable type, you can use the Value
property:
int ageNonNullable = age.Value; // Ensure age is not null before accessing Value.
Nullable Types and Operations
When working with nullable types, it is important to understand how they behave in arithmetic and logical operations.
Arithmetic Operations
Arithmetic operations with nullable types follow specific rules: if any of the operands is null
, the result is also null
.
int? a = 10;
int? b = null;
int? sum = a + b;
Console.WriteLine(sum.HasValue ? sum.Value.ToString() : "null"); // Prints null
Here, because b
is null
, the sum results in null
.
Comparisons
Comparisons with nullable types are possible, but the result can be null
if any of the operands is null
.
int? x = 10;
int? y = null;
bool? isGreater = x > y;
Console.WriteLine(isGreater.HasValue ? isGreater.Value.ToString() : "null"); // Prints null
In this case, isGreater
is null
because y
is null
.
Improvements in C# 8.0 and Later Versions
Starting from C# 8.0, the ability to distinguish between nullable and non-nullable types was introduced in the language’s type system.
This means you can mark a type as “nullable” and the compiler will warn you if you try to assign a null value to a type that should not accept nulls.
#nullable enable
public class Person
{
public string Name { get; set; } // Cannot be null
public string? LastName { get; set; } // Can be null
}