null
References; Introducing C# 6’s ?.
OperatorIn Section 13.6, we showed the following code snippet:
{ var exampleObject = new ExampleClass(); try { exampleObject.SomeMethod(); } finally { if (exampleObject != null) { exampleObject.Dispose(); } } }
The if
statement in the preceding finally
block ensures that if exampleObject
is null
, the call to Dispose
is skipped, thus preventing a NullReferenceException
.
Always ensure that a reference is not null
before using it to call a method or access a property of an object.
?.
)6 C# 6’s new null-conditional operator (?.
) provides a more elegant way to check for null
. The following statement replaces the four-line if
statement above:
exampleObject?.Dispose();
In this statement, Dispose
is called only if exampleObject
is not null
—exactly as in the preceding if
statement.
is
and as
In Section 12.5.6, we introduced downcasting with the is
operator and mentioned that downcasting can cause InvalidCastException
s. We then mentioned that you can avoid the InvalidCastException
by using the as
operator as follows:
var employee = currentEmployee as BasePlusCommissionEmployee;
If currentEmployee
is a BasePlusCommissionEmployee
, employee
is assigned the Base-PlusCommissionEmployee
; otherwise, it’s assigned null
. Since employee
could be null
, you must ensure that it’s not null
before using it. For example, to give the BasePlusCommissionEmployee
a 10% raise, we could use the statement
employee?.BaseSalary *= 1.10M;
which accesses and modifies the BaseSalary
property only if employee
is not null
.
Suppose you’d like to capture the value of the expression employee?.BaseSalary
, as in
decimal salary = employee?.BaseSalary;
This statement actually results in a compilation error indicating that you cannot implicitly convert type decimal?
to type decimal
.
Normally a value-type variable cannot be assigned null
. Because the employee
reference might be null
, the expression
employee?.BaseSalary
returns a nullable type—a value type that also can be null
. You specify a nullable type by following a value type’s name with a question mark (?
)—so decimal?
represents a nullable
decimal? salary = employee?.BaseSalary;
indicates that salary
either will be null
or the employee
’s BaseSalary
.
Nullable types have the following capabilities for accessing their underlying values:
The GetValueOrDefault
method checks whether a nullable-type variable contains a value. If so, the method returns that value; otherwise, it returns the value type’s default value. An overload of this method receives one argument that enables you to specify a custom default value.
The HasValue
property returns true
if a nullable-type variable contains a value; otherwise, it returns false
.
The Value
property returns the nullable-type variable’s underlying value or throws an InvalidOperationException
if the underlying value is null
.
Variables of nullable types also may be used as the left operand of the null-conditional operator (?.
) or the null coalescing operator (??
—discussed in the next section).
Before using a nullable-type variable’s Value
property, use the HasValue
property to check whether the variable has a value. If the nullable-type variable is null
, accessing Value
results in an InvalidOperationException
.
??
)C# also offers the null coalescing operator (??
) for working with values that can be null
. The operator has two operands. If the left operand is not null
, the entire ??
expression evaluates to the left operand’s value; otherwise, it evaluates to the right operand’s value. For example, in the statement
decimal salary = employee?.BaseSalary ?? 0M;
if employee
is not null
, salary
is assigned the employee
’s BaseSalary
; otherwise, salary
is assigned 0M
. The preceding statement is equivalent to
decimal salary = (employee?.BaseSalary).GetValueOrDefault();
As you can see, the preceding statements are more elegant and more compact than writing the following equivalent code, which must explicitly test for null
:
decimal salary = 0M;
if (employee != null)
{
salary = employee.BaseSalary
}