C# > Language Features by Version > C# 6 to C# 12 Highlights > Nullable Reference Types (C# 8)
Nullable Reference Types and Collections
This snippet extends the previous example to show how nullable reference types work with collections (specifically, a List). It demonstrates how to handle collections that might contain null values when nullable reference types are enabled.
Creating a List with Nullable Strings
Here, we create a List
of string?
. This means the list can contain either strings or null values. The string?
type parameter allows us to explicitly indicate that nulls are permitted in the list.
List<string?> names = new List<string?> { "Alice", null, "Bob", null, "Charlie" };
Iterating and Handling Nulls
When iterating through the list, we need to check each element for null before attempting to use it. The if (name != null)
check ensures that we only call ToUpper()
on non-null strings. Without this check, a NullReferenceException
would occur when name
is null.
foreach (string? name in names)
{
if (name != null)
{
Console.WriteLine("Name: " + name.ToUpper());
}
else
{
Console.WriteLine("Null name found.");
}
}
Filtering Nulls from a Collection
This shows how to create a new list containing only the non-null strings from the original list. We use the Where
extension method to filter out null values and the ToList()
method to create a new List
. Because we are filtering out the nulls, the compiler knows that the list contains non-nullable strings. The null-forgiving operator is necessary because ToList()
could potentially return null if the source sequence is empty or null, but the Where
filter ensures that it will never be null in this case (because even if the source list contains only nulls, the resulting list will be empty not null). Note that the type of `nonNullNames` is `List
List<string> nonNullNames = names.Where(name => name != null).ToList()!;
foreach (string name in nonNullNames)
{
Console.WriteLine("Non-Null Name: " + name.ToUpper());
}
Alternatives with Null-Coalescing Operator
This provides an alternative approach using the null-coalescing operator (??
). If `name` is null, the value `(Unknown)` is assigned to `safeName`; otherwise, `name` is assigned to `safeName`. This ensures that `safeName` is never null, eliminating the need for a separate null check before calling `ToUpper()`.
foreach (string? name in names)
{
string safeName = name ?? "(Unknown)";
Console.WriteLine("Name: " + safeName.ToUpper());
}
Concepts Behind Nullable Reference Types and Collections
Applying Nullable Reference Types to collections is important for ensuring type safety. It makes it explicit whether a collection can contain null values or not. For example, a List<string?>
signals that nulls are permitted, while a List<string>
guarantees non-null elements. This enables more robust code and reduces the risk of runtime errors.
Real-Life Use Case
Imagine retrieving data from a database where some fields might be null. When mapping the database results to a list of objects, you might encounter null values. Using nullable reference types with collections allows you to handle these potential nulls gracefully, ensuring that your code doesn't crash with unexpected NullReferenceExceptions. For instance, you might load a list of products from a database, where the `Description` property could be nullable.
Best Practices
List<string?>
vs. List<string>
).Where
) to filter out null values from collections.
Interview Tip
Be prepared to discuss how nullable reference types affect the usage of collections. Demonstrate your understanding of how to iterate through collections containing nullable values and how to filter out nulls. You may also be asked to explain the benefits of using nullable reference types with collections in terms of type safety and code reliability.
FAQ
-
What happens if I try to add a null value to a
List<string>
when nullable reference types are enabled?
The compiler will issue a warning becauseList<string>
expects non-nullable strings. To allow null values, you need to useList<string?>
. -
Is there a performance overhead when using nullable reference types with collections?
Nullable reference types themselves do not introduce any runtime performance overhead. However, the additional null checks might add a small overhead. In most cases, this overhead is negligible compared to the benefits of improved code safety.