Skip to Content
Course content

230: Null-Forgiving Operator

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

Sometimes, you and the C# compiler simply disagree. You know—based on the architecture of your app, a database constraint, or a validation check that happened five method calls ago—that a variable cannot possibly be null. The compiler, however, only sees the type definition and insists on giving you a warning. This is where the null-forgiving operator (the ! symbol) comes in.

Think of the ! operator as a "shush" button. You aren't changing the runtime behavior of the code; you aren't checking for nulls or providing defaults. You are simply telling the compiler, "I've got this. Stop worrying about this specific reference."

Setting up a "Trust Me" scenario

Let's look at a common situation: a class that gets populated by an external framework (like an ORM or a JSON deserializer). I'll build a simple UserSession class. In a real app, the SessionId would be guaranteed by the database, but the compiler doesn't know that.

public class UserSession
{
    // The compiler sees this as nullable because it's not set in the constructor
    public string? SessionId { get; set; }

    public void LogCurrentSession()
    {
        // Warning: Possible null reference assignment.
        Console.WriteLine($"Current Session: {SessionId.Length}");
    }
}

If I try to access SessionId.Length, the compiler flags it. It's doing its job. But if this class is only ever instantiated after a successful login where the ID is guaranteed, the warning is just noise.

The temptation of the redundant check

When I first encountered this, my instinct was to just "fix" the warning with a standard null check. I'll show you what I did in a similar project a while back, and why it was actually a mistake in that context.

public void LogCurrentSession()
{
    if (SessionId == null) 
    {
        throw new InvalidOperationException("SessionId should never be null here.");
    }
    
    Console.WriteLine($"Current Session: {SessionId.Length}");
}

Now the warning is gone, but I've added a runtime branch and a potential exception to a piece of code that runs thousands of times a second. If I am 100% certain that the framework has already validated this object before it reached this method, I'm adding overhead and clutter for no real gain. I'm coding defensively to satisfy a compiler, not to handle a real business requirement.

Using the null-forgiving operator correctly

Instead of adding runtime checks, I can use the ! operator. I'll place it immediately after the variable name to tell C# that I am taking responsibility for this value.

public void LogCurrentSession()
{
    // "Trust me, SessionId is not null."
    Console.WriteLine($"Current Session: {SessionId!.Length}");
}

Notice that SessionId! doesn't actually do anything when the program runs. It's a compile-time instruction only. If SessionId actually happens to be null at runtime, you'll still get a NullReferenceException. That's why you should use this sparingly. It's a tool for when you have external knowledge that the compiler lacks.

I usually reserve this for three specific cases: unit tests where I've manually set up the state, legacy code integration, and properties initialized by dependency injection or database mappers. If you find yourself putting ! everywhere, you aren't "fixing" warnings—you're just turning off the safety features of the language.




📋 Practical Task

Fixing the ProductRepository Warning

You are working on a ProductRepository class. The _connectionString field is assigned during a Initialize() method that is called at application startup. Because it's not assigned in the constructor, the compiler is complaining that _connectionString might be null when used in the GetConnection() method.

Modify the code below to remove the compiler warning using the null-forgiving operator. Do not use an if statement or a null-coalescing operator, as the team has already decided that a runtime crash is preferable to a redundant check in this performance-critical path.

public class ProductRepository
{
    private string? _connectionString;

    public void Initialize(string connectionString)
    {
        _connectionString = connectionString;
    }

    public string GetConnection()
    {
        // TODO: Use the null-forgiving operator to remove the warning 
        // and return the _connectionString.
        return _connectionString; 
    }
}
Rating
0 0

There are no comments for now.

to be the first to leave a comment.