While reference types can be null (when they refer to no object) value types can not.
This is because a reference type variable is a "pointer" to a memory address and so one such address is reserved to be "null" but in the case of a value type there is no space available to signify the lack of a value - somebody declaring byte for example will want all 256 possible values.
In C# 1 you had to choose between adding a "missing value" flag or reserving a special value to indicate the absence of a value.
A Nullable<T> type was added that wraps the value type with a boolean to flag the presence or absence of a value. The compiler allows the result to be treated as having null semantics, and provides the shorthand T? (a ? suffix on the type name) as an alias for Nullable<T>.
Code
int? quantity = int.TryParse(txtQuantity.Value, out var parsed)
? parsed
: null;
updateOrderLine(quantity);int quantity = 0;
bool quantityProvided = txtQuantity.Value != ""
&& int.TryParse(txtQuantity.Value, out quantity);
updateOrderLine(quantityProvided ? quantity : -1); // -1 = missingNotes
- Operators are "lifted" so
a + bon twoint?values givesnullif either isnull - Use
HasValue/Value,GetValueOrDefault()or the null-coalescing operator C# 2.0 to get the underlying value - Writing
: nullin the "Now" conditional relies on Target-typed conditional expression C# 9.0; earlier versions need(int?)null - An alternative way to achieve this in C# 1 was to use the NullableTypes open-source project that provided hand-crafted wrapper types for each of the built-in .NET value types