Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions docs/csharp/fundamentals/null-safety/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
title: "Null safety in C#"
description: Learn how C# helps you write null-safe code using nullable value types, nullable reference types, and null operators.
ms.date: 04/30/2026
ms.topic: overview
ai-usage: ai-assisted
---

# C# null safety

> [!TIP]
> This article is part of the **Fundamentals** section for developers who already know at least one programming language and are learning C#. If you're new to programming, start with the [Get started](../../tour-of-csharp/tutorials/index.md) tutorials first.
>
> **Coming from Java or C++?** C# provides compile-time null safety through nullable reference types. The goal is similar to Java's `@NonNull` annotations but enforced by the compiler. C# also has dedicated operators like `?.` and `??` that make null-safe expressions concise.

`null` represents the absence of a value. When you try to access a member on a `null` reference, by calling a method or reading a property, the runtime throws a <xref:System.NullReferenceException>:

:::code language="csharp" source="snippets/null-safety-overview/Program.cs" ID="NullReferenceDemo":::

C# gives you three complementary tools to write null-safe code:

- **Nullable value types**: let a value type like `int` or `bool` also hold `null`
- **Nullable reference types**: let the compiler track whether a reference might be `null`
- **Null operators**: express null-safe access and fallback logic concisely

## Nullable value types

Value types like `int`, `double`, and `bool` can't hold `null` by default. Add `?` to the type name to create a *nullable value type* that holds either a value or `null`:

:::code language="csharp" source="snippets/null-safety-overview/Program.cs" ID="NvtIntro":::

Nullable value types are useful when an underlying value type needs to represent "no data." Common scenarios include database columns that might be absent, optional configuration settings, and sensor readings that aren't captured yet.

For full coverage of declaration, checking, and conversion, see [Nullable value types](nullable-value-types.md).

## Nullable reference types

Reference types, such as `string`, arrays, and class instances, can hold `null` at runtime. *Nullable reference types* is a compiler feature that makes null intent explicit and catches mistakes at compile time.

By using the `?` annotation, you declare your intent:

- `string?` — this reference *might* be `null`; the compiler warns if you dereference it without checking first
- `string` — this reference *should not* be `null`; the compiler warns if you assign `null` to it

:::code language="csharp" source="snippets/null-safety-overview/Program.cs" ID="NrtIntro":::

All .NET projects that modern SDK templates create enable nullable reference types by default. For complete guidance on enabling and annotating, see [Nullable reference types](../../nullable-references.md).

## Null operators

C# includes several operators that let you write null-safe code without manual `if`-null guards everywhere:

| Operator | Name | Purpose |
|---------------------------|---------------------------------|--------------------------------------------------------|
| `?.` | Null-conditional member access | Access a member only when the object is non-null |
| `?[]` | Null-conditional indexer access | Access an element only when the collection is non-null |
| `??` | Null-coalescing | Return a fallback value when the expression is `null` |
| `??=` | Null-coalescing assignment | Assign only when the variable is `null` |
| `is null` / `is not null` | Null pattern | Preferred null test |

:::code language="csharp" source="snippets/null-safety-overview/Program.cs" ID="OperatorsQuickRef":::

For detailed examples of each operator, see [Null operators](null-operators.md).

## Nullable value types and nullable reference types serve different purposes

Nullable value types and nullable reference types aren't alternatives. They solve different problems:

- Use `T?` for a value type that needs to represent "no value." For example, use `int?` for an optional database column or `DateTime?` for an event that isn't scheduled yet.
- Use `string?` and other nullable reference annotations to document that a reference *might* be `null`, so the compiler can warn you before a `NullReferenceException` occurs at runtime.

Together, these features and the null operators give you a complete set of tools to write null-safe C# code.
106 changes: 106 additions & 0 deletions docs/csharp/fundamentals/null-safety/null-operators.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
---
title: "Null operators in C#"
description: Learn how to use the null-conditional (?. and ?[]), null-coalescing (??), null-coalescing assignment (??=), and null pattern (is null) operators to write null-safe C# code.
ms.date: 04/30/2026
ms.topic: concept-article
ai-usage: ai-assisted
---

# C# null operators

> [!TIP]
> This article is part of the **Fundamentals** section for developers who know at least one programming language and are learning C#. If you're new to programming, start with the [Get started](../../tour-of-csharp/tutorials/index.md) tutorials first. For the complete operator reference, see [Member access operators](../../language-reference/operators/member-access-operators.md) and [null-coalescing operators](../../language-reference/operators/null-coalescing-operator.md) in the language reference.

C# provides several operators that make null-safe code concise. Instead of nesting `if (x != null)` guards throughout your code, these operators let you express null-safe access, fallback values, and null tests in a single expression.

This article covers `?.` and `?[]` for null-conditional access, `??` for null-coalescing, `??=` for null-coalescing assignment, and `is null`/`is not null` for null pattern matching.

## Null-conditional member access `?.`

The `?.` operator accesses a member only when the object is non-null. When the object is `null`, the entire expression evaluates to `null` instead of throwing a <xref:System.NullReferenceException>:

:::code language="csharp" source="snippets/null-operators/Program.cs" ID="NullConditionalMember":::

The `?.` operator *short-circuits*: when the left-hand side is `null`, everything to the right is skipped. No method calls run and no side effects occur.

You can chain multiple `?.` operators in a single expression. The chain stops at the first `null` it encounters:

:::code language="csharp" source="snippets/null-operators/Program.cs" ID="NullConditionalMemberChain":::

## Null-conditional indexer access `?[]`

The `?[]` operator applies the same short-circuit behavior to indexer and array access. Use it when the collection itself might be `null`:

:::code language="csharp" source="snippets/null-operators/Program.cs" ID="NullConditionalIndexer":::

## Chain null-conditional operators

Chain multiple `?.` operators to traverse a path of potentially null references. The chain short-circuits at the first `null`:

:::code language="csharp" source="snippets/null-operators/Program.cs" ID="NullConditionalChain":::

When `Customer` is `null`, neither `Address` nor `City` is evaluated. The whole expression returns `null`.

## Thread-safe delegate invocation

`?.` provides a clean, thread-safe way to invoke a delegate or raise an event. The delegate expression is evaluated only once, so there's no window for another thread to unsubscribe between the null check and the invocation:

:::code language="csharp" source="snippets/null-operators/Program.cs" ID="NullConditionalDelegate":::

This pattern replaces the older `if (clicked != null) clicked(...)` idiom.

## Null-coalescing `??`

The `??` operator returns its left-hand operand when it's non-null, and its right-hand operand when the left is `null`. Use it to provide a default value:

:::code language="csharp" source="snippets/null-operators/Program.cs" ID="NullCoalescing":::

`??` is right-associative, so `a ?? b ?? c` evaluates as `a ?? (b ?? c)`. The first non-null value wins. A common pattern is to chain `?.` with `??`: use `?.` to safely traverse a null-possible chain, then `??` to substitute a default if the chain returned `null`. For a complete example, see [Combine null operators](#combine-null-operators).

## Null-coalescing assignment `??=`

The `??=` operator assigns the right-hand value to a variable only when the variable is `null`. Use it for lazy initialization:

:::code language="csharp" source="snippets/null-operators/Program.cs" ID="NullCoalescingAssignment":::

The right-hand expression is evaluated only when the variable is `null`. When the variable already has a value, the right side isn't evaluated at all.

## Null-conditional assignment (C# 14)

Beginning in C# 14, you can use `?.` and `?[]` as assignment targets. The assignment runs only when the left-hand object is non-null:

:::code language="csharp" source="snippets/null-operators/Program.cs" ID="NullConditionalAssignment":::

The right-hand side is evaluated only when the left-hand side is known to be non-null.

## Null pattern matching: `is null` and `is not null`

The `is null` and `is not null` patterns test whether an expression is `null`:

:::code language="csharp" source="snippets/null-operators/Program.cs" ID="IsNull":::

Prefer `is null` over `== null` for null checks. The `==` operator can be overloaded, meaning `x == null` might return `true` even when `x` isn't `null` if the type defines a custom equality operator. The `is null` pattern always tests for the actual null reference, regardless of operator overloading.

:::code language="csharp" source="snippets/null-operators/Program.cs" ID="IsNotNull":::

## Combine null operators

In practice, you often combine several of these operators. One expression can safely traverse a deep object graph, apply a fallback, and then guard on the result:

:::code language="csharp" source="snippets/null-operators/Program.cs" ID="CombinedPattern":::

## Null-forgiving operator `!`

The `!` postfix operator suppresses nullable warnings. Append `!` to tell the compiler "this expression is definitely not null." The operator has no effect at runtime. It only affects the compiler's null-state analysis.

:::code language="csharp" source="snippets/null-operators/Program.cs" ID="NullForgiving":::

Use `!` sparingly, and only when you have information the compiler doesn't. Examples include tests that intentionally pass `null` to validate argument-checking logic, or calling a method whose contract guarantees a non-null return for a known input. Overusing `!` defeats the purpose of nullable reference types. For a full explanation, see [Nullable reference types](../../nullable-references.md).

## See also

- [Null safety overview](index.md)
- [Nullable value types](nullable-value-types.md)
- [Nullable reference types](../../nullable-references.md)
- [Member access operators (language reference)](../../language-reference/operators/member-access-operators.md)
- [Null-coalescing operators (language reference)](../../language-reference/operators/null-coalescing-operator.md)
69 changes: 69 additions & 0 deletions docs/csharp/fundamentals/null-safety/nullable-value-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
title: "Nullable value types: C# Fundamentals"
description: Learn how to use nullable value types (T?) in C# to represent value types that can be absent or undefined.
ms.date: 04/30/2026
ms.topic: concept-article
ai-usage: ai-assisted
---

# Nullable value types: C# Fundamentals

> [!TIP]
> This article is part of the **Fundamentals** section for developers who know at least one programming language and are learning C#. If you're new to programming, start with the [Get started](../../tour-of-csharp/tutorials/index.md) tutorials first. For more details, see [Nullable value types](../../language-reference/builtin-types/nullable-value-types.md) in the language reference.

A *nullable value type* `T?` represents all values of its underlying value type `T`, plus an additional `null` value. A variable of type `int?` holds any integer or `null` to represent "no value."

Value types like `int`, `bool`, and `DateTime` can't hold `null` by default. This behavior is efficient and prevents many errors. However, this limitation creates a problem when a value might genuinely be absent. A common scenario is reading from a database: an integer column might contain a number, or it might contain no value at all (`NULL` in SQL). A plain `int` can't represent that absence, but `int?` can.

## Declare a nullable value type

Append `?` to any value type to make it nullable:

:::code language="csharp" source="snippets/nullable-value-types/Program.cs" ID="Declaration":::

The default value of a nullable value type is `null`, not the underlying type's default.

## Check whether a value is present

The recommended way to check a nullable value type and extract its value is with a *type pattern*:

:::code language="csharp" source="snippets/nullable-value-types/Program.cs" ID="PatternMatching":::

The `is int degrees` pattern matches only when `temperature` is non-null, and it simultaneously binds the value to `degrees`. You get both the null check and the value extraction in one step.

Alternatively, use the `HasValue` and `Value` properties:

:::code language="csharp" source="snippets/nullable-value-types/Program.cs" ID="HasValue":::

Prefer the `is T value` pattern for new code. It introduces a new non-nullable variable scoped to the matched branch, which makes the intent clearer and eliminates any temptation to accidentally use `Value` outside a null check, where it would throw an <xref:System.InvalidOperationException>.

You can also compare directly with `null`:

:::code language="csharp" source="snippets/nullable-value-types/Program.cs" ID="NullCheck":::

## Get a value with a fallback

When you need a non-nullable value from a nullable, use `GetValueOrDefault` or the null-coalescing `??` operator:

:::code language="csharp" source="snippets/nullable-value-types/Program.cs" ID="GetValueOrDefault":::

The `??` operator is often cleaner inline:

:::code language="csharp" source="snippets/nullable-value-types/Program.cs" ID="NullCoalescing":::

Both approaches return the actual value when one is present, and the fallback you specify when it isn't.

## Arithmetic with nullable value types

Arithmetic and comparison operators on nullable value types are *lifted*: when either operand is `null`, the result is `null` rather than an error.

:::code language="csharp" source="snippets/nullable-value-types/Program.cs" ID="LiftedOperators":::

Null propagates through arithmetic by default. To prevent a null result from cascading further, extract the value with `??` or `GetValueOrDefault` before you use it in a calculation.

## See also

- [Null safety overview](index.md)
- [Null operators](null-operators.md)
- [Nullable value types (language reference)](../../language-reference/builtin-types/nullable-value-types.md)
- [Nullable reference types](../../nullable-references.md)
Loading
Loading