CodeGym /Courses /C# SELF /Analyzing Compiler Warnings

Analyzing Compiler Warnings

C# SELF
Level 14, Lesson 4
Available

1. Introduction

Imagine your code is a play, and variables are the actors. Every time a variable enters a new scene (code block), it can be "alive" (has a value) or a "ghost" (null). But here's the catch: the audience—the compiler—watches the play not live, but by reading the script. It sees where actors get their roles (assigned values), and where they disappear (become null). But it can't peek into reality (program execution)—it can only guess from the script!

Static flow analysis is the process where the compiler checks your code before running the program, trying to figure out if someone is about to play the "NullReferenceException crash" scene.

The gist of it

Starting with C# 8.0 and the Nullable Reference Types (NRT) mode, the compiler checks if a variable could be null in any execution branch. If yes—it tells you right away. It won't let you "use the name of an actor who suddenly turned into a ghost."

2. How to read compiler warnings

Main categories of warnings

When NRT mode is on, the compiler pays extra attention to reference variables (string, User, arrays, objects). Here are the most common warning types:

  • Possible null assignment — you're trying to assign a value that could be null to a variable that doesn't allow null.
  • Dereference of a possibly null reference — you're accessing a member of an object, but the compiler isn't sure it's not null.
  • Possible null return — a method might return null even though its signature says it must return a value.
  • Nullable object must have a value — you're using .Value on a nullable type without checking it first.
  • Unassigned non-nullable property — you didn't assign a value to a field/property that can't be null.

Usually in your IDE (like Rider or Visual Studio), these warnings are underlined with a squiggly line, and if you hover your mouse, you'll see an explanation.

Example of a typical warning


#nullable enable

string? possibleNull = GetString();

// Uh-oh, compiler complains: "Dereference of a possibly null reference"
int length = possibleNull.Length; // Warning!

The compiler isn't sure that possibleNull isn't null, so accessing .Length could throw an exception.

If your method looks like this:

string? GetString() { ... }

And you write:

string nonNullable = GetString();

You'll get a warning: possible unsafe assignment of null to a non-nullable variable.

3. The compiler analyzes your code

Example 1: straight-up assignment


string? name = null;
Console.WriteLine(name.Length); // Warning: possible null reference

Pretty obvious here: name is null, so trying to access its property is risky.

Example 2: null check


string? name = GetUserName();

if (name != null)
{
    Console.WriteLine(name.Length); // All good!
}
else
{
    Console.WriteLine("Name not provided!");
}

The compiler gets that inside the if (name != null) block, the variable is safe. That's flow analysis—tracking values depending on conditions.

4. The compiler can't peek "inside the method"

It only looks at the signature—if it says the method returns string?, it trusts that it could be null, even if it always returns a string inside.

Example 3: returning a value from a method


string? GetMaybeName(bool useName)
{
    if (useName)
        return "Code Jedi";
    else
        return null;
}

void PrintLength()
{
    string? name = GetMaybeName(false);

    Console.WriteLine(name.Length); // Warning!
}

The compiler sees that GetMaybeName could return null, so it wants you to be careful.

5. Common scenarios and warnings

Assigning nullable to non-nullable variable


string? maybeUser = GetUser();
string alwaysUser = maybeUser; // warning: possible null assignment

To fix the warning:


string alwaysUser = maybeUser ?? "Guest";

Now you'll always have a string—either from the method or "Guest".

Forgot to check .HasValue on a nullable value type


int? age = GetAge();
int realAge = age.Value; // warning: possible null reference

You should do it like this:


if (age.HasValue)
    Console.WriteLine(age.Value);

Or:


int realAge = age ?? -1;

Auto-properties without initialization


class User
{
    public string Name { get; set; } // warning: not initialized!
}

Ways to fix:


public string Name { get; set; } = "No name";

or


public string? Name { get; set; }

6. Tricky flow analysis cases

Analysis in loops


string? text = null;

while (text == null)
{
    text = Console.ReadLine();
}

Console.WriteLine(text.Length); // all good: compiler figured it out!

Different assignment paths


string? name;
if (Random.Shared.Next() % 2 == 0)
    name = "Alice";
else
    name = null;

Console.WriteLine(name.Length); // warning: possible null dereference

The compiler checks all branches. If there's null in at least one—it warns you.

7. How to "calm down" the compiler (and when you shouldn't)

Sometimes you're sure the value can't be null, but the compiler doesn't buy it:


string? value = GetSomething();
if (value == null)
    throw new Exception("Expected a value!");

Console.WriteLine(value.Length); // Warning goes away

Or you use the ! operator:


string? value = GetSomething();
Console.WriteLine(value!.Length); // No warnings, but risky

This is called the null-forgiving operator. It doesn't check anything—it just tells the compiler: "chill, I've got this." But if you're wrong—you'll get an exception at runtime.

2
Task
C# SELF, level 14, lesson 4
Locked
Null check before using a variable
Null check before using a variable
2
Task
C# SELF, level 14, lesson 4
Locked
Eliminating warnings using the null-coalescing operator
Eliminating warnings using the null-coalescing operator
1
Survey/quiz
Nullable Types, level 14, lesson 4
Unavailable
Nullable Types
Intro to Nullable Reference Types
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION