How to use nullable reference types in C#

Nullable reference types, introduced in C# 8.0, help prevent null reference exceptions by making nullability explicit. Enable them with <Nullable>enable</Nullable> in your project file or #nullable enable in code.

A type followed by ? (like string?) indicates it can be null. Types without ? should never be null, and the compiler warns you about potential null dereferences.

The null-forgiving operator ! tells the compiler you know a value isn't null, suppressing warnings. Use it sparingly when you have information the compiler doesn't.

C# Example Code
#nullable enable
using System;

public class NullableReferenceTypes
{
    public static void Main(string[] args)
    {
        // Non-nullable reference type (cannot be null)
        string name = "Alice";
        Console.WriteLine($"Length: {name.Length}");  // Safe

        // Nullable reference type (can be null)
        string? nullableName = null;
        // Console.WriteLine(nullableName.Length);  // Warning: possible null reference

        // Safe null checking
        if (nullableName != null)
        {
            Console.WriteLine($"Length: {nullableName.Length}");
        }

        // Null-conditional operator
        int? length = nullableName?.Length;
        Console.WriteLine($"Length: {length ?? 0}");

        // Null-forgiving operator (use carefully!)
        string? possiblyNull = GetValue();
        string definitelyNotNull = possiblyNull!;  // Tells compiler it's not null
        Console.WriteLine(definitelyNotNull);

        // Method with nullable parameters
        PrintMessage(null);  // OK, parameter is nullable
        PrintMessage("Hello");

        // Method with non-nullable parameter
        // PrintRequired(null);  // Warning: passing null to non-nullable parameter
        PrintRequired("Required");
    }

    static string? GetValue()
    {
        return "Some value";
    }

    static void PrintMessage(string? message)
    {
        // Safe handling of nullable parameter
        Console.WriteLine(message ?? "No message");
    }

    static void PrintRequired(string message)
    {
        // message is guaranteed to not be null (by contract)
        Console.WriteLine($"Required: {message.ToUpper()}");
    }

    // Properties with nullable reference types
    class Person
    {
        public string Name { get; set; } = "";  // Non-nullable, must initialize
        public string? MiddleName { get; set; }  // Nullable, can be null
        public string LastName { get; set; } = "";

        public string GetFullName()
        {
            return MiddleName != null
                ? $"{Name} {MiddleName} {LastName}"
                : $"{Name} {LastName}";
        }
    }
}