Skip to content
Merged
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
25 changes: 20 additions & 5 deletions docs/csharp/language-reference/builtin-types/ref-struct.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "ref struct types - C# reference"
description: Learn about the ref struct type in C#
ms.date: 09/15/2022
ms.date: 10/12/2022
---
# `ref` structure types (C# reference)

Expand All @@ -18,8 +18,6 @@ You can use the `ref` modifier in the declaration of a [structure type](struct.m

You can define a disposable `ref struct`. To do that, ensure that a `ref struct` fits the [disposable pattern](~/_csharplang/proposals/csharp-8.0/using.md#pattern-based-using). That is, it has an instance or extension `Dispose` method, which is accessible, parameterless and has a `void` return type.

Beginning with C# 11, a `ref struct` may contain `ref` fields. To declare a `ref` field, use the same syntax as for declaring a [`ref` local variable](../statements/declarations.md#ref-locals). A `ref` field may be reassigned after it's initialized. The compiler ensures that a reference stored in a `ref` field doesn't outlive the value to which it refers. For information about the scope rules, see the [Scope of reference and values](../keywords/method-parameters.md#scope-of-references-and-values) section of the [Method parameters](../keywords/method-parameters.md) article.

Typically, you define a `ref struct` type when you need a type that also includes data members of `ref struct` types:

:::code language="csharp" source="snippets/shared/StructType.cs" id="SnippetRefStruct":::
Expand All @@ -30,15 +28,32 @@ To declare a `ref struct` as `readonly`, combine the `readonly` and `ref` modifi

In .NET, examples of a `ref struct` are <xref:System.Span%601?displayProperty=nameWithType> and <xref:System.ReadOnlySpan%601?displayProperty=nameWithType>.

## `ref` fields

Beginning with C# 11, you can declare a `ref` field in a `ref struct`, as the following example shows:

:::code language="csharp" source="snippets/shared/StructType.cs" id="SnippetRefField":::

A `ref` field may have the `null` value. Use the <xref:System.Runtime.CompilerServices.Unsafe.IsNullRef%60%601(%60%600@)?displayProperty=nameWithType> method to determine if a `ref` field is `null`.

You can apply the `readonly` modifier to a `ref` field in the following ways:

- `readonly ref`: You can [ref reassign](../operators/assignment-operator.md#ref-assignment) such a field with the `= ref` operator only inside a constructor or an [`init` accessor](../keywords/init.md). You can assign a value with the `=` operator at any point allowed by the field access modifier.
- `ref readonly`: At any point, you cannot assign a value with the `=` operator to such a field. However, you can ref reassign a field with the `= ref` operator.
- `readonly ref readonly`: You can only ref reassign such a field in a constructor or an `init` accessor. At any point, you cannot assign a value to the field.

The compiler ensures that a reference stored in a `ref` field doesn't outlive the value to which it refers. For information about the scope rules, see the [Scope of reference and values](../keywords/method-parameters.md#scope-of-references-and-values) section of the [Method parameters](../keywords/method-parameters.md) article.

## C# language specification

For more information, see the [Structs](~/_csharpstandard/standard/structs.md) section of the [C# language specification](~/_csharpstandard/standard/README.md).

For more information about features introduced in C# 7.2 and later, see the following feature proposal notes:

- [C# 7.2 - Compile-time safety for ref-like types](~/_csharplang/proposals/csharp-7.2/span-safety.md)
- [C# 11 - ref fields and scoped](~/_csharplang/proposals/csharp-11.0/low-level-struct-improvements.md)

## See also

- [C# reference](../index.md)
- [The C# type system](../../fundamentals/types/index.md)
- [C# 7.2 - Compile-time safety for ref-like types](~/_csharplang/proposals/csharp-7.2/span-safety.md)
- [C# 11 - ref fields and scoped](~/_csharplang/proposals/csharp-11.0/low-level-struct-improvements.md)
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,23 @@ public ConversionRequest(double rate, ReadOnlySpan<double> values)
public ReadOnlySpan<double> Values { get; }
}
// </SnippetReadonlyRef>

// <SnippetRefField>
public ref struct RefFieldExample
{
private ref int number;

public int GetNumber()
{
if (System.Runtime.CompilerServices.Unsafe.IsNullRef(ref number))
{
throw new InvalidOperationException("The number ref field is not initialized.");
}

return number;
}
}
// </SnippetRefField>
}

namespace parameterless_constructor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ All of the changes that take place inside the method affect the original array i
Methods can store the values of parameters in fields. When parameters are passed by value, that's always safe. Values are copied, and reference types are reachable when stored in a field. Passing parameters by reference safely requires the compiler to define when it's safe to assign a reference to a new variable. For every expression, the compiler defines a *scope* that bounds access to an expression or variable. The compiler uses two scopes: *safe_to_escape* and *ref_safe_to_escape*.

- The *safe_to_escape* scope defines the scope where any expression can be safely accessed.
- The *ref_safe_to_escape* scope defines the scope where a *reference* to any expressions can be safely accessed or modified
- The *ref_safe_to_escape* scope defines the scope where a *reference* to any expression can be safely accessed or modified.

Informally, you can think of these scopes as the mechanism to ensure your code never accesses or modifies a reference that's no longer valid. A reference is valid as long as it refers to a valid object or struct. The *safe_to_escape* scope defines when a variable can be assigned or reassigned. The *ref_safe_to_escape* scope defines when a variable can *ref* assigned or *ref* reassigned. Assignment assigns a variable to a new value. *ref assignment* assigns the variable to *refer to* a different storage location.
Informally, you can think of these scopes as the mechanism to ensure your code never accesses or modifies a reference that's no longer valid. A reference is valid as long as it refers to a valid object or struct. The *safe_to_escape* scope defines when a variable can be assigned or reassigned. The *ref_safe_to_escape* scope defines when a variable can *ref* assigned or *ref* reassigned. Assignment assigns a variable to a new value; *ref assignment* assigns the variable to *refer to* a different storage location.

## Modifiers

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ This is called *value assignment*: the value is assigned.

## ref assignment

*Ref assignment* `= ref` makes its left-hand operand an alias to the right-hand operand. The left-hand operand must be a [ref local](../keywords/ref.md#ref-locals), [ref readonly local](../keywords/ref.md#ref-readonly-locals), or a `ref` field in a [`ref struct`](../builtin-types/ref-struct.md). Both operands must be of the same type.
*Ref assignment* `= ref` makes its left-hand operand an alias to the right-hand operand. The left-hand operand must be a [ref local](../keywords/ref.md#ref-locals), [ref readonly local](../keywords/ref.md#ref-readonly-locals), or a [`ref` field](../builtin-types/ref-struct.md#ref-fields) in a `ref struct`. Both operands must be of the same type.

The following example demonstrates the usage of the ref assignment operator:

Expand Down