Skip to Content
Course content

247: Common C# Interview Questions on Nullable Reference Types

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

If you're heading into a C# interview, you can bet your bottom dollar that Nullable Reference Types (NRTs) will come up. Interviewers love them because they test whether you actually understand the difference between what the compiler thinks and what the runtime actually does. It's a subtle distinction that trips up a lot of people.

Let's look at this through a practical lens. I'm going to build a small UserProfile class, and we'll see where the compiler starts complaining.

The Warning That Won't Go Away

I'll start with a simple class. I'm assuming we have <Nullable>enable</Nullable> turned on in the project file, which is the default for most modern .NET templates.

public class UserProfile
{
    public string Username { get; set; }
    public string Bio { get; set; }
}

// In my Main method:
var profile = new UserProfile();
profile.Username = "DevGuru";
// I'm intentionally skipping Bio here.

Right away, the IDE is screaming at me. I've got a warning: "Non-nullable property 'Bio' must contain a non-null value when exiting constructor."

Now, if this were old-school C#, this would be fine. Bio would just be null. But with NRTs, I've told the compiler that Bio is a string, not a string?. By omitting the question mark, I'm making a promise: "This will never be null." The compiler sees that I haven't provided a value in the constructor and calls me out on my lie.

Pushing the Problem Downstream

Okay, let's "fix" that by making the Bio optional. That's a common real-world scenario—not everyone wants to write a bio.

public class UserProfile
{
    public string Username { get; set; } = string.Empty; // Fixed the Username warning too
    public string? Bio { get; set; } // Notice the '?'
}

The warning in the class definition is gone. Great. But now watch what happens when I try to use that Bio. This is where the interview questions usually pivot to "how do you handle the nulls?"

var profile = new UserProfile { Username = "DevGuru" };
int bioLength = profile.Bio.Length; 

Boom. Another warning: "Dereference of a possibly null reference." The compiler is essentially saying, "You told me Bio could be null, and now you're trying to access .Length without checking first. You're playing with fire."

To solve this, I could use an if statement, but in a professional codebase, I'm usually reaching for the null-coalescing operator to provide a fallback.

int bioLength = (profile.Bio ?? "No bio provided").Length;

Fighting the Compiler (and Losing)

Here is a question that comes up constantly: "What is the null-forgiving operator, and when should you use it?"

You've probably seen the ! operator (the "bang" operator). Let's say I have a piece of logic where I know for a fact that the Bio isn't null because of some external validation I did elsewhere that the compiler can't see.

// I'm telling the compiler: "Shut up, I know what I'm doing."
int bioLength = profile.Bio!.Length; 

The warning vanishes. But here is the critical part—and the part you must mention in an interview: The ! operator does absolutely nothing at runtime. It is a directive for the compiler only. If profile.Bio actually is null, your program will still crash with a NullReferenceException. Using ! is essentially taking a gamble that your assumptions are correct.

The Runtime Reality Check

This leads to the final, most important distinction. I've seen candidates lose points here. They think NRTs change how the C# language works at a fundamental level. They don't.

Let's prove it. I'll try to force a null into my "non-nullable" Username property using a cast.

var profile = new UserProfile();
profile.Username = null!; // Using the bang to bypass the warning

The code compiles. I run it. It runs perfectly fine. The Username is now null, despite me declaring it as string. This proves that NRTs are a static analysis feature. They are like a very helpful spell-checker for nulls, but they don't add any actual "guards" or runtime checks to your variables. If you can find a way to sneak a null in there, the runtime won't stop you until you try to use that null.




📋 Practical Task

Fixing the Fragile CustomerOrder System

You've inherited a CustomerOrder class that is riddled with NRT warnings and potential runtime crashes. Your goal is to make the code "compiler-clean" without using the null-forgiving operator (!) unless absolutely necessary, and ensuring the code is safe from NullReferenceExceptions.

public class CustomerOrder
{
    public int OrderId { get; set; }
    public string CustomerName { get; set; } // Warning: Non-nullable property must contain a non-null value
    public string? ShippingAddress { get; set; }
    public string OrderNotes { get; set; } // Warning: Non-nullable property must contain a non-null value

    public void PrintOrderSummary()
    {
        // Warning: Dereference of a possibly null reference
        Console.WriteLine($"Shipping to: {ShippingAddress.ToUpper()}");
        
        // This is safe, but the compiler doesn't know that yet
        Console.WriteLine($"Notes: {OrderNotes}");
    }
}

Requirements:

  • Ensure CustomerName is initialized so the constructor warning disappears.
  • Make OrderNotes optional (nullable) since not all orders have notes.
  • Fix the PrintOrderSummary method so it doesn't crash if ShippingAddress is null. Use the null-coalescing operator (??) to print "No address provided" instead of calling ToUpper() on a null value.
  • Ensure the final class has zero compiler warnings.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.