-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C#
-
Section 4: Working with Data
-
Section 5: Error Handling
-
Section 6: Delegates and Events
-
Section 7: Async Programming
-
Section 8: More Language Features
-
Section 9: File I/O and Serialization
-
Section 10: Networking in .NET
-
Section 11: The .NET Ecosystem
-
Section 12: Memory and Performance
-
Section 13: Concurrency Beyond Async
-
Section 14: Reflection and Attributes
-
Section 15: Testing and Best Practices
-
Section 16: Design Patterns in C#
-
Section 17: Standard Library Deep Dive
-
Section 18: Data Structures and Algorithms in C#
-
Section 19: GUI and Desktop Development Overview
-
Section 20: Practical Projects
-
Section 21: More Practice Exercises
-
Section 22: More Standard Library and Text Processing
-
Section 23: More Design Patterns
-
Section 24: More Projects
-
Section 25: Interview Practice
-
Section 26: C# Keywords Reference (Modifiers)
-
Section 27: C# Keywords Reference (Statements)
-
Section 28: C# Keywords Reference (Operators)
-
Section 29: BCL: System.Collections.Generic
-
Section 30: BCL: System.Linq
-
Section 31: BCL: System.Threading
-
Section 32: BCL: System.IO
-
Section 33: BCL: System.Text and System.Text.Json
-
Section 34: BCL: System.Net.Http
-
Section 35: C# Language Specification Topics
-
Section 36: More Practice Exercises
-
Section 37: More Async Patterns
-
Section 38: More BCL: System.Reflection and System.Diagnostics
-
Section 39: Nullable Reference Types In Depth
-
Section 40: C# Records and Pattern Matching In Depth
-
Section 41: Dependency Injection Deep Dive
-
Section 42: More Interview and Whiteboard Practice
247: Common C# Interview Questions on Nullable Reference Types
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
CustomerNameis initialized so the constructor warning disappears. - Make
OrderNotesoptional (nullable) since not all orders have notes. - Fix the
PrintOrderSummarymethod so it doesn't crash ifShippingAddressis null. Use the null-coalescing operator (??) to print "No address provided" instead of callingToUpper()on a null value. - Ensure the final class has zero compiler warnings.
There are no comments for now.