Pour obtenir une clé
d'essai remplissez le formulaire ci-dessous
Demandez des tariffs
Nouvelle licence
Renouvellement de licence
--Sélectionnez la devise--
USD
EUR
RUB
* En cliquant sur ce bouton, vous acceptez notre politique de confidentialité

Free PVS-Studio license for Microsoft MVP specialists
To get the licence for your open-source project, please fill out this form
** En cliquant sur ce bouton, vous acceptez notre politique de confidentialité.

I am interested to try it on the platforms:
** En cliquant sur ce bouton, vous acceptez notre politique de confidentialité.

Message submitted.

Your message has been sent. We will email you at


If you haven't received our response, please do the following:
check your Spam/Junk folder and click the "Not Spam" button for our message.
This way, you won't miss messages from our team in the future.

>
>
>
Nullable Value Types

Nullable Value Types

14 Jul 2021

Nullable value type is a type that allows you to represent not only all values of its underlying type, but also the null value.

General Info

Why do we need nullable value types? For example, an int type variable can have values ranging from -2,147,483,648 to 2,147,483,647. Some cases require specification that a variable value is not defined or missing. For example, a column value in a database row. Nullable value types have been created for such cases. These types are instances of the System.Nullable<T> structure.

You can define an int variable that allows null as follows:

Nullable<int> nullableInt;

However, a shortened entry is more common:

int? nullableInt;

For the above C# declarations, the same IL code will be generated.

Both values of the underlying type and null are written to a variable via simple assignment:

int? nullableIntLhs = 62;
int? nullableIntRhs = null;

Properties

The HasValue property allows you to find out whether a variable of nullable value type contains a value of the underlying type:

int? iNullable = 62;
int result;
if (iNullable.HasValue)
  result = iNullable.Value;
else
  result = -1;
// result == 62

In addition to calling the HasValue property, you can check for a value by comparing to null. The following checks are equal, the same IL code generates for them:

int? nullableInt = null;
bool hasValue1 = nullableInt.HasValue;
bool hasValue2 = nullableInt != null;

The Value property returns the value of the underlying type if there is one (Nullable<T>.HasValue - true). Otherwise, we'll get the InvalidoperationException:

int? iNullable = ....;
int result;
if (iNullable.HasValue)
  result = iNullable.Value; // OK
else
  result = iNullable.Value; // InvalidOperationException

Methods

The T GetValueOrDefault() method is basically similar to Value. The difference is that T GetValueOrDefault() doesn't throw an exception, but returns a default value of T type if there is no value of the underlying type:

int? iNullable = ....;
int result;
if (!iNullable.HasValue)
  result = iNullable.GetValueOrDefault(); // result == 0

The T GetValueOrDefault (T defaultValue) method is similar to the Value property. The only difference is that it does not generate an exception. It returns the value of the DefaultValue argument if there is no value of the underlying type:

int? iNullable = ....;
int result;
if (!iNullable.HasValue)
  result = iNullable.GetValueOrDefault(62); // result == 62

Conversion Operators

For Nullable<T>, there are defined operators: implicit conversion from T to Nullable<T> and explicit conversion from Nullable<T> to T.

You can assign T values to Nullable<T> variables directly:

Nullable<int> nullableInt;
nullableInt = 62;

To write a value from Nullable<T> to a T variable, you will need to perform explicit casting. If the underlying value is missing (Nullable<T>.HasValue - false) in Nullable<T>, we'll get InvalidOperationException when performing explicit casting.

Example:

Nullable<int> nullableIntLhs = 62;
int resultLhs = (int)nullableIntLhs; // OK, 62
Nullable<int> nullableIntRhs = null;
int resultRhs = (int)nullableIntRhs; // InvalidOperationException

Specifications of Using Nullable Value Types

Nullable<T> can't have the null value

This may be confusing given what you've read above. Besides, the following code is successfully compiling:

Nullable<int> nullableInt = null;

However, you should remember that Nullable<int> is a value type. Hence null here is just syntax sugar. In this case, the nullableInt variable will be initialized with the default(Nullable<int>) value.

All the variables below will have the same value:

Nullable<int> nInt1 = null;
Nullable<int> nInt2 = new Nullable<int>();
Nullable<int> nInt3 = default(Nullable<int>);

int? nInt4 = null;
int? nInt5 = new int?();
int? nInt6 = default(int?);

It becomes more obvious if you look at IL code, where the same value is explicitly used to initialize all variables:

IL_0001:  ldloca.s   nInt1
IL_0003:  initobj    valuetype [mscorlib]System.Nullable`1<int32>
IL_0009:  ldloca.s   nInt2
IL_000b:  initobj    valuetype [mscorlib]System.Nullable`1<int32>
IL_0011:  ldloca.s   nInt3
IL_0013:  initobj    valuetype [mscorlib]System.Nullable`1<int32>
IL_0019:  ldloca.s   nInt4
IL_001b:  initobj    valuetype [mscorlib]System.Nullable`1<int32>
IL_0021:  ldloca.s   nInt5
IL_0023:  initobj    valuetype [mscorlib]System.Nullable`1<int32>
IL_0029:  ldloca.s   nInt6
IL_002b:  initobj    valuetype [mscorlib]System.Nullable`1<int32>

Boxing and Unboxing

Boxing of Nullable<T> values has a number of specifications:

  • suppose Nullable<T>.HasValue — true. Then not the Nullable<T> instance itself is boxed, but the value of the underlying type - Nullable<T>.Value;
  • if Nullable<T>.HasValue is false, the result of the boxing will be null;
  • if null is unboxed, the result is default(Nullable<T>).

Operators Defined for T

If unary and binary operators (for example, '+', '-') are supported by T, then the following rule applies to Nullable<T>:

  • if the value of at least one operand is null, the result is null;
  • if both operands are not null, the resulting value is the result of the operator for the underlying values of operands (Nullable<T>.Value).

Results table:

NullableValueTypes/image1.png

For greater/less comparison operators ('<', '<=', '>', '>='):

  • if at least one of the operands is null, the result is false;
  • if both operands are not null, the resulting value is the result of the operator for the underlying values of operands (Nullable<T>.Value).

Results table:

NullableValueTypes/image2.png

Equality operator ('=='):

  • if both operands are null, the result is true;
  • if one operand is null, the other is not null, the result is false;
  • if both operands are not null, the resulting value is the result of the '==' operator for the values of the underlying type.

Results table:

NullableValueTypes/image3.png

Inequality operator ('!='):

  • if both operands are null, the result is false;
  • if one operand is null, the other is not null, the result is true;
  • if both operands are not null, the resulting value is the result of the '!=' operator for the values of the underlying type.

Results table:

NullableValueTypes/image4.png

Operator '&':

  • if both operands are null, the result is null;
  • if one operand is null, the other is true, the result is null;
  • if one operand is null, the other is false, the result is false;
  • if both operands are not null, the resulting value is lhs & rhs.

Results table:

NullableValueTypes/image5.png

Operator '|':

  • if both operands are null, the result is null;
  • if one operand is null, the other is false, the result is null;
  • if one operand is null, the other is true, the result is true;
  • if both operands are not null, the resulting value is lhs | rhs.

Results table:

NullableValueTypes/image6.png

Additional links

Comments (0)

Next comments
Unicorn with delicious cookie
Nous utilisons des cookies pour améliorer votre expérience de navigation. En savoir plus
Accepter