Course contentsShow
← C#
Lesson 270 of 1,9083. Generics and Collections ArchitectureFree lesson

Reference Type Nullability Constraints

Leverage the class constraint to differentiate between nullable and non-nullable reference types in generics.

In this lesson, you will learn how to use generic constraints to enforce whether a type parameter must be a non-nullable reference type or if it allows nulls.

The Problem with Generics and Nulls

When you define a generic class or method, the compiler often doesn't know if the type argument T is a value type or a reference type. Even worse, it doesn't know if T is intended to be "nullable" (like string?) or "non-nullable" (like string).

If we want to create a component that strictly handles non-nullable references—for example, a database cache that refuses to store null values—we need a way to tell the compiler to reject nullable inputs.

Using the class Constraint

To enforce that a generic type must be a non-nullable reference type, we use the class constraint combined with C#'s nullable reference type features.

When you apply the class constraint, the compiler treats T as a non-nullable reference type by default. If a user tries to pass a nullable type (like string?), the compiler will issue a warning or error, helping you maintain strict architectural boundaries.

public class DataProcessor<T> where T : class
{
    // Because of 'where T : class', T is treated as non-nullable.
    public void Process(T item) 
    {
        // We are guaranteed that 'item' is not null.
        Console.WriteLine(item.ToString());
    }
}

Why This Matters

If you omit the class constraint, the compiler assumes T could be anything—a struct, a class, or a nullable type. By explicitly stating where T : class, you communicate your architectural intent clearly: this component is designed specifically for reference types that are expected to contain valid data.

This approach prevents "null-propagation" bugs from leaking into your collections or domain services. It moves the responsibility of null-checking from inside your methods to the type-checking phase of the compiler, making your generic architecture much more robust and predictable.

Key Takeaway: Use the where T : class constraint to guarantee that your generic code only accepts non-nullable reference types, effectively preventing nulls from entering your architectural components at compile time.