diff --git a/docs/csharp/language-reference/builtin-types/ref-struct.md b/docs/csharp/language-reference/builtin-types/ref-struct.md index 394fe07cb2376..4c34ca77acb6b 100644 --- a/docs/csharp/language-reference/builtin-types/ref-struct.md +++ b/docs/csharp/language-reference/builtin-types/ref-struct.md @@ -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) @@ -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"::: @@ -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 and . +## `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 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) diff --git a/docs/csharp/language-reference/builtin-types/snippets/shared/StructType.cs b/docs/csharp/language-reference/builtin-types/snippets/shared/StructType.cs index b54963f26903e..004b2a3d70b2f 100644 --- a/docs/csharp/language-reference/builtin-types/snippets/shared/StructType.cs +++ b/docs/csharp/language-reference/builtin-types/snippets/shared/StructType.cs @@ -125,6 +125,23 @@ public ConversionRequest(double rate, ReadOnlySpan values) public ReadOnlySpan Values { get; } } // + + // + 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; + } + } + // } namespace parameterless_constructor diff --git a/docs/csharp/language-reference/keywords/method-parameters.md b/docs/csharp/language-reference/keywords/method-parameters.md index 94d6442409768..192d1836d41e2 100644 --- a/docs/csharp/language-reference/keywords/method-parameters.md +++ b/docs/csharp/language-reference/keywords/method-parameters.md @@ -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 diff --git a/docs/csharp/language-reference/operators/assignment-operator.md b/docs/csharp/language-reference/operators/assignment-operator.md index 88efdd515317a..749b9ec7ee3cd 100644 --- a/docs/csharp/language-reference/operators/assignment-operator.md +++ b/docs/csharp/language-reference/operators/assignment-operator.md @@ -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: