From bf806c2211cfabe793b8c11ea5d4ca6c92c11813 Mon Sep 17 00:00:00 2001 From: pkulikov Date: Tue, 11 Oct 2022 21:02:42 +0200 Subject: [PATCH 1/6] Added more docs for ref fields --- .../builtin-types/ref-struct.md | 20 ++++++++++++++++--- .../snippets/shared/StructType.cs | 17 ++++++++++++++++ .../keywords/method-parameters.md | 6 +++--- .../operators/assignment-operator.md | 2 +- 4 files changed, 38 insertions(+), 7 deletions(-) diff --git a/docs/csharp/language-reference/builtin-types/ref-struct.md b/docs/csharp/language-reference/builtin-types/ref-struct.md index eaf3d45c68b03..d49234fbe888a 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/14/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,6 +28,22 @@ 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). 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..d181d67739807 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 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 0aee590372a7a..192d1836d41e2 100644 --- a/docs/csharp/language-reference/keywords/method-parameters.md +++ b/docs/csharp/language-reference/keywords/method-parameters.md @@ -81,12 +81,12 @@ All of the changes that take place inside the method affect the original array i ## Scope of references and values -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 its 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*. +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: From 062b1b69b80b4f13f328696ead6996ee250af6df Mon Sep 17 00:00:00 2001 From: pkulikov Date: Tue, 11 Oct 2022 21:05:50 +0200 Subject: [PATCH 2/6] Minor edits --- docs/csharp/language-reference/builtin-types/ref-struct.md | 2 +- .../builtin-types/snippets/shared/StructType.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/csharp/language-reference/builtin-types/ref-struct.md b/docs/csharp/language-reference/builtin-types/ref-struct.md index d49234fbe888a..d77942e5e1feb 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: 10/14/2022 +ms.date: 10/12/2022 --- # `ref` structure types (C# reference) 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 d181d67739807..004b2a3d70b2f 100644 --- a/docs/csharp/language-reference/builtin-types/snippets/shared/StructType.cs +++ b/docs/csharp/language-reference/builtin-types/snippets/shared/StructType.cs @@ -135,7 +135,7 @@ public int GetNumber() { if (System.Runtime.CompilerServices.Unsafe.IsNullRef(ref number)) { - throw new InvalidOperationException("The number field is not initialized."); + throw new InvalidOperationException("The number ref field is not initialized."); } return number; From f53676a155528899f153c54035470ecf7571d2a2 Mon Sep 17 00:00:00 2001 From: pkulikov Date: Tue, 11 Oct 2022 21:19:30 +0200 Subject: [PATCH 3/6] Try to fix a xref link --- docs/csharp/language-reference/builtin-types/ref-struct.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/language-reference/builtin-types/ref-struct.md b/docs/csharp/language-reference/builtin-types/ref-struct.md index d77942e5e1feb..444a6f5752285 100644 --- a/docs/csharp/language-reference/builtin-types/ref-struct.md +++ b/docs/csharp/language-reference/builtin-types/ref-struct.md @@ -34,7 +34,7 @@ Beginning with C# 11, you can declare a `ref` field in a `ref struct`, as the fo :::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`. +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: From 5c7f407b7d7c2186e354d10271eafb69dcfdbf41 Mon Sep 17 00:00:00 2001 From: pkulikov Date: Tue, 11 Oct 2022 21:21:15 +0200 Subject: [PATCH 4/6] Moved the spec links --- docs/csharp/language-reference/builtin-types/ref-struct.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/csharp/language-reference/builtin-types/ref-struct.md b/docs/csharp/language-reference/builtin-types/ref-struct.md index 615937c4cb5e9..bdda48e2bd65b 100644 --- a/docs/csharp/language-reference/builtin-types/ref-struct.md +++ b/docs/csharp/language-reference/builtin-types/ref-struct.md @@ -50,9 +50,10 @@ For more information, see the [Structs](~/_csharpstandard/standard/structs.md) s 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) From ca638fb03436a6295fbf98d3846e3594ba1c42ef Mon Sep 17 00:00:00 2001 From: pkulikov Date: Tue, 11 Oct 2022 21:42:09 +0200 Subject: [PATCH 5/6] Revert xref --- docs/csharp/language-reference/builtin-types/ref-struct.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/language-reference/builtin-types/ref-struct.md b/docs/csharp/language-reference/builtin-types/ref-struct.md index bdda48e2bd65b..1c39efd80b8a2 100644 --- a/docs/csharp/language-reference/builtin-types/ref-struct.md +++ b/docs/csharp/language-reference/builtin-types/ref-struct.md @@ -34,7 +34,7 @@ Beginning with C# 11, you can declare a `ref` field in a `ref struct`, as the fo :::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`. +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: From fa3df99a0b06f5bde146d9d45e8945da193f7344 Mon Sep 17 00:00:00 2001 From: Petr Kulikov Date: Wed, 12 Oct 2022 19:08:00 +0200 Subject: [PATCH 6/6] Update docs/csharp/language-reference/builtin-types/ref-struct.md Co-authored-by: Bill Wagner --- docs/csharp/language-reference/builtin-types/ref-struct.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/language-reference/builtin-types/ref-struct.md b/docs/csharp/language-reference/builtin-types/ref-struct.md index 1c39efd80b8a2..4c34ca77acb6b 100644 --- a/docs/csharp/language-reference/builtin-types/ref-struct.md +++ b/docs/csharp/language-reference/builtin-types/ref-struct.md @@ -34,7 +34,7 @@ Beginning with C# 11, you can declare a `ref` field in a `ref struct`, as the fo :::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`. +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: