Skip to Content
Course content

41: Nullable Types and Null Safety

Click on the "Edit" button in the top corner of the screen to edit your slide content.

You've probably seen it. Maybe it was your first day on the job, or maybe it was last week. The NullReferenceException. It's the most infamous error in C# because it usually happens in the one edge case you forgot to account for. Let's look at a piece of code that looks perfectly fine at first glance but is actually a ticking time bomb.

public class UserProfile
{
    public string FirstName { get; set; }
    public string MiddleName { get; set; } // Some users don't have one
    public string LastName { get; set; }
}

public class UserDisplay
{
    public string GetFullName(UserProfile profile)
    {
        // This looks clean, right?
        return $"{profile.FirstName} {profile.MiddleName.ToUpper()} {profile.LastName}";
    }
}

If you run this with a user who has a middle name, it works great. But the second you pass in a profile where MiddleName is null, the app crashes. Why? Because you're trying to call .ToUpper() on a reference that points to nothing. You can't perform an operation on a void.

Stopping the Crash with Null-Conditional Operators

In the old days, we'd wrap everything in if (profile.MiddleName != null) blocks. It worked, but it made the code bloated and hard to read. Now, we have the null-conditional operator (?.). This operator tells C#: "If the thing on the left is null, stop right here and just return null for the whole expression. Don't try to call the method."

However, if we just use profile.MiddleName?.ToUpper(), our return type becomes a nullable string, and we might end up with a weird "null" string printed in our UI. That's where the null-coalescing operator (??) comes in. It lets us provide a fallback value.

public string GetFullName(UserProfile profile)
{
    // If MiddleName is null, the ?. stops the chain.
    // If the result of that chain is null, the ?? kicks in and uses an empty string.
    string middle = profile.MiddleName?.ToUpper() ?? "";
    
    return $"{profile.FirstName} {middle} {profile.LastName}".Replace("  ", " ").Trim();
}

Defining Intent with Nullable Reference Types

The real problem with the first example wasn't just the crash—it was that the UserProfile class lied to us. It claimed MiddleName was a string, implying it should always have a value. In modern C#, we use Nullable Reference Types (NRTs) to be honest about our data.

By adding a ? to the type, you're telling the compiler (and other developers), "Heads up: this value might actually be null."

public class UserProfile
{
    public string FirstName { get; set; } = string.Empty;
    public string? MiddleName { get; set; } // Explicitly nullable
    public string LastName { get; set; } = string.Empty;
}

Once you enable Nullable Reference Types in your project settings, the compiler stops being a passive observer. If you try to call profile.MiddleName.ToUpper() without a null check, you'll get a warning in your IDE. I actually love these warnings; they're essentially the compiler saying, "I've seen this bug a thousand times, and you're about to make it again."

Handling Value Types with Nullable

One quick distinction: string is a reference type, but int or bool are value types. Value types can't be null by default—an int is always at least 0. But what if you're dealing with a database where a "Age" column can be empty? You can't use 0, because 0 is a valid age for a newborn.

For these, we use int? (which is shorthand for Nullable<int>). These wrappers have a HasValue property and a Value property.

int? userAge = null;

if (userAge.HasValue)
{
    Console.WriteLine($"Age is {userAge.Value}");
}
else
{
    Console.WriteLine("Age not provided");
}

My advice? Be aggressive with ?. If a piece of data isn't 100% guaranteed to exist, mark it as nullable. It forces you to handle the edge cases while you're writing the code, rather than discovering them via a crash report in production.




📋 Practical Task

Fixing the Product Inventory Null Guard

You are working on an e-commerce system. There is a Product class where the DiscountPrice is optional (nullable), and the Description might be null if the vendor didn't provide one. The current code is crashing when products are missing this information.

Your Task: Modify the GetProductSummary method to prevent NullReferenceExceptions. Use the null-conditional operator (?.) and the null-coalescing operator (??) to ensure that:

  • If Description is null, it displays "No description available".
  • If DiscountPrice is null, it displays "Full Price". Otherwise, it displays the price formatted as currency.
public class Product
{
    public string Name { get; set; } = "Unknown Product";
    public string? Description { get; set; }
    public decimal? DiscountPrice { get; set; }
}

public class ProductService
{
    public string GetProductSummary(Product product)
    {
        // TODO: Fix the following lines to prevent crashes and handle nulls
        string desc = product.Description.Trim(); 
        string price = product.DiscountPrice.Value.ToString("C");

        return $"Product: {product.Name} | Description: {desc} | Price: {price}";
    }
}
Rating
0 0

There are no comments for now.

to be the first to leave a comment.