Back to Blog
C#

C# Nullable Value Property: Syntax and Usage

c# nullable value property: Learn how to declare nullable value properties in C#, check for null with HasValue, and handle missing values safely.

C#nullable typesvalue typesnull handlingproperties
Diagram of a C# nullable value property showing a question mark and two states: a number and an empty box.

A value type property in C# cannot be null by default. If you need to represent an optional integer, boolean, or other value type, you must explicitly declare it as nullable. The ? suffix on a value type creates a Nullable<T> instance that can hold either a value or null. This is the foundation of the C# nullable value property pattern.

Declaring a Nullable Value Property

The syntax for a nullable value property is straightforward. Add ? to the value type:

public class Person { public int? Age { get; set; } public bool? IsActive { get; set; } }

int? is a shorthand for Nullable<int>. The property's default value is null, not zero. This is important because it distinguishes "not set" from "set to zero". You can also assign a value directly:

person.Age = 30; person.Age = null; // clears the value

Checking for a Value with HasValue and Value

Every nullable value type exposes two members: HasValue and Value. HasValue returns true when the property holds a non-null value. Value returns the underlying value, but throws InvalidOperationException if HasValue is false.

if (person.Age.HasValue) { Console.WriteLine($"Age is {person.Age.Value}"); } else { Console.WriteLine("Age is unknown"); }

Since C# 7.0, you can use pattern matching to combine the check and extraction:

if (person.Age is int age) { Console.WriteLine($"Age is {age}"); }

This avoids the separate Value access and is often cleaner.

Reading and Writing Nullable Properties Safely

The null-coalescing operator ?? provides a default value when the property is null:

int displayAge = person.Age ?? 0;

For a default value of the underlying type, GetValueOrDefault() is more concise:

int displayAge = person.Age.GetValueOrDefault();

You can also pass a custom default to GetValueOrDefault(int defaultValue). When writing, you can assign either a value or null. There is no need to call Nullable<T>.Clear; assigning null works.

Nullable Value Types in DTOs and Database Mapping

Nullable value properties are common in data transfer objects (DTOs) and database models. A null value often means "field not provided" or "no data". For example, a user profile might have an optional age:

public class UserProfile { public string Name { get; set; } public int? Age { get; set; } }

When mapping from a database row, a null column maps naturally to a null property. This is particularly relevant when using ORMs like Entity Framework Core, where nullable columns are represented as nullable properties. This design avoids using sentinel values like -1 or int.MinValue to indicate missing data.

Performance and Memory Considerations

Nullable<T> is a struct that contains an underlying value and a boolean flag. This means a nullable property uses more memory than the bare value type. For most applications the difference is negligible, but in high-performance or memory-sensitive code, consider whether the extra byte (or alignment padding) matters.

Boxing is another concern. When you assign a nullable value type to an object or an interface, the runtime boxes the entire struct, not just the underlying value. This can cause allocation overhead in code that frequently converts nullable values to reference types. Avoid boxing in hot paths by using HasValue and Value directly.

Common Mistakes and Edge Cases

One common mistake is accessing Value without checking HasValue. This throws an exception at runtime. Always use ??, GetValueOrDefault(), or pattern matching.

Comparing nullable properties with == works as expected: two null values are equal, and a null value is not equal to a non-null value. However, comparing with a non-nullable value requires care:

if (person.Age == 30) // works, returns false if null

This compiles because the int? is implicitly converted to int? for comparison.

Another edge case is the interaction with nullable reference types (enabled with #nullable enable). Nullable value types are independent; the ? on a value type is not the same as ? on a reference type. A string? property can be null, but an int? property is a nullable value type. The compiler treats them differently.

Choosing Between Nullable Value Types and Alternative Approaches

Sometimes developers use a separate boolean flag to indicate whether a value is set, or a sentinel value like -1. These approaches are error-prone and obscure the intent. A nullable value property is the idiomatic C# way to represent an optional value type.

Use a nullable value property when:

  • The value is genuinely optional and the absence of a value is meaningful.
  • You are mapping to a database column that allows NULL.
  • You want the compiler to help you handle the null case.

Avoid nullable value properties when:

  • The value is always present and a default is acceptable.
  • The overhead of the extra boolean flag matters in a performance-critical path.
  • You need to distinguish between "not set" and "set to default" but the default is also a valid value; in that case, consider a custom struct or an explicit flag.

The decision ultimately comes down to whether null is a meaningful state in your domain. If it is, int? is the right tool. If not, stick with a plain int and use 0 or another default.

c# nullable value property: Practical Usage and Code Example | RYUSLOG DEV