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
4 changes: 3 additions & 1 deletion docfx.json
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@
"_csharplang/proposals/csharp-10.0/*.md": "08/07/2021",
"_csharplang/proposals/csharp-11.0/*.md": "09/30/2022",
"_csharplang/proposals/csharp-12.0/*.md": "08/15/2023",
"_csharplang/proposals/*.md": "05/15/2024",
"_csharplang/proposals/*.md": "06/28/2024",
"_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md": "11/08/2022",
"_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 8.md": "09/26/2023",
"_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md": "06/26/2024",
Expand Down Expand Up @@ -662,6 +662,7 @@
"_csharplang/proposals/lock-object.md": "Obey lock object semantics for lock statements",
"_csharplang/proposals/method-group-natural-type-improvements.md": "Method group natural type improvements",
"_csharplang/proposals/params-collections.md": "Params collections",
"_csharplang/proposals/ref-unsafe-in-terators-async.md": "Allow ref and unsafe in iterators and async methods",
"_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md": "C# compiler breaking changes since C# 10",
"_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 8.md": "C# compiler breaking changes since C# 11",
"_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md": "C# compiler breaking changes since C# 12",
Expand Down Expand Up @@ -778,6 +779,7 @@
"_csharplang/proposals/lock-object.md": "Special-case how `System.Threading.Lock` interacts with the `lock` keyword by calling its `EnterScope` method. Add static analysis warnings to prevent accidental misuse of the type where possible.",
"_csharplang/proposals/method-group-natural-type-improvements.md": "This proposal refines the determination of the natural type of a method group by considering candidates scope-by-scope and pruning at each scope.",
"_csharplang/proposals/params-collections.md": "Allow the `params` modifier on collection types beyond arrays, including `IEnumerable` types.",
"_csharplang/proposals/ref-unsafe-in-terators-async.md": "This proposal modifies restrictions to enable ref local variables and unsafe blocks in iterators and async methods",
"_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md": "Learn about any breaking changes since the initial release of C# 10",
"_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 8.md": "Learn about any breaking changes since the initial release of C# 11",
"_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md": "Learn about any breaking changes since the initial release of C# 12",
Expand Down
14 changes: 7 additions & 7 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"
description: Learn about the ref struct type in C#
ms.date: 10/12/2022
ms.date: 06/28/2024
---
# `ref` structure types (C# reference)

Expand All @@ -12,9 +12,9 @@ You can use the `ref` modifier in the declaration of a [structure type](struct.m
- A `ref struct` can't implement interfaces.
- A `ref struct` can't be boxed to <xref:System.ValueType?displayProperty=nameWithType> or <xref:System.Object?displayProperty=nameWithType>.
- A `ref struct` can't be a type argument.
- A `ref struct` variable can't be captured by a [lambda expression](../operators/lambda-expressions.md) or a [local function](../../programming-guide/classes-and-structs/local-functions.md).
- A `ref struct` variable can't be used in an [`async`](../keywords/async.md) method. However, you can use `ref struct` variables in synchronous methods, for example, in methods that return <xref:System.Threading.Tasks.Task> or <xref:System.Threading.Tasks.Task%601>.
- A `ref struct` variable can't be used in [iterators](../../iterators.md).
- A `ref struct` variable can't be captured in a [lambda expression](../operators/lambda-expressions.md) or a [local function](../../programming-guide/classes-and-structs/local-functions.md).
- Before C# 13,`ref struct` variables can't be used in an `async` method. Beginning with C# 13, a `ref struct` variable can't be used in the same block as the [`await`](../operators/await.md) expression in an [`async`](../keywords/async.md) method. However, you can use `ref struct` variables in synchronous methods, for example, in methods that return <xref:System.Threading.Tasks.Task> or <xref:System.Threading.Tasks.Task%601>.
- Before C# 13, a `ref struct` variable can't be used in [iterators](../../iterators.md). Beginning with C# 13, `ref struct` types and `ref` locals can be used in iterators, provided they aren't in code segments with the `yield return` statement.

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 `Dispose` method, which is accessible, parameterless and has a `void` return type. You can use the [using statement or declaration](../statements/using.md) with an instance of a disposable `ref struct`.

Expand All @@ -34,13 +34,13 @@ 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 <xref:System.Runtime.CompilerServices.Unsafe.IsNullRef%60%601(%60%600@)?displayProperty=nameWithType> method to determine if a `ref` field is `null`.
A `ref` field can 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.
- `ref readonly`: At any point, you can't 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 can't assign a value to the field.

The compiler ensures that a reference stored in a `ref` field doesn't outlive its referent.

Expand Down
8 changes: 5 additions & 3 deletions docs/csharp/language-reference/compiler-messages/cs1996.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
description: "Compiler Error CS1996"
title: "Compiler Error CS1996"
ms.date: 9/12/2022
ms.date: 7/01/2024
f1_keywords:
- "CS1996"
helpviewer_keywords:
Expand All @@ -13,7 +13,7 @@ Cannot await in the body of a lock statement

## Example

The following sample generates CS1996:
The following sample generates CS1996:

```csharp
public class C
Expand All @@ -33,9 +33,11 @@ public class C
}
```

The preceding code produces the same error with C# 13, as the `await` is in the `lock` statement block.

## To correct this error

Asynchronous code within a `lock` statement block is hard to implement reliably and even harder to implement in a general sense. The C# compiler doesn't support doing this to avoid emitting code that will be prone to deadlocks. Extracting the asynchronous code from the `lock` statement block will correct this error. For example:
Asynchronous code within a `lock` statement block is hard to implement reliably and even harder to implement in a general sense. The C# compiler doesn't support doing this to avoid emitting code prone to deadlocks. Extracting the asynchronous code from the `lock` statement block corrects this error. For example:

```csharp
public class C
Expand Down
8 changes: 5 additions & 3 deletions docs/csharp/language-reference/compiler-messages/cs4004.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
description: "Compiler Error CS4004"
title: "Compiler Error CS4004"
ms.date: 9/12/2022
ms.date: 07/01/2024
f1_keywords:
- "CS4004"
helpviewer_keywords:
Expand All @@ -13,7 +13,7 @@ Cannot await in an unsafe context

## Example

The following sample generates CS4004:
The following sample generates CS4004:

```csharp
using System.Threading.Tasks;
Expand Down Expand Up @@ -47,11 +47,13 @@ public static class C
}
```

This code generates an error in C# 13 because the `await` is in the `unsafe` block.

The `ReverseText` method naively uses a background task to asynchronously create a new string in reverse order of a given string.

## To correct this error

Separating the unsafe code from the awaitable code will correct this error. One separation technique is creating a new method for the unsafe code and then calling it from the awaitable code. For example:
Separating the unsafe code from the awaitable code corrects this error. One separation technique is creating a new method for the unsafe code and then calling it from the awaitable code. For example:

```csharp
public static class C
Expand Down
34 changes: 30 additions & 4 deletions docs/csharp/language-reference/compiler-messages/cs4013.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
description: "Compiler Error CS4013"
title: "Compiler Error CS4013"
ms.date: 9/12/2022
ms.date: 06/28/2024
f1_keywords:
- "CS4013"
helpviewer_keywords:
Expand All @@ -11,6 +11,8 @@ helpviewer_keywords:

Instance of type cannot be used inside a nested function, query expression, iterator block or async method

Beginning with C# 13, `ref struct` types can be used in iterator methods, if they aren't accessed across `yield return` statement.

## Example

The following sample generates CS4013:
Expand All @@ -34,11 +36,11 @@ public class C
}
```

This enumerator method extracts lines of text from a character array. It naively tries to use `ReadOnlySpan<T>` to improve performance.
This enumerator method extracts lines of text from a character array. It naively tries to use `ReadOnlySpan<T>` to improve performance. The preceding example exhibits the same error in C# 13, because the `ReadOnlySpan` instance `chars` is in scope at the `yield return` statement.

## To correct this error

`Lines(char[] text)` is an enumerator function. An enumerator function compiles the method's body into a state machine that manages the sequence of states the iterator function goes through while processing. That state machine is implemented as a generated class, and the state is implemented as variables within that class. That captured local state is forced from a stack context to a heap context. Since `ref struct`s like `ReadOnlySpan<T>` cannot be stored in the heap, the CS4013 error is raised. To continue to use a `ReadOnlySpan<T>`, to correct this error, the method must be re-implemented as a non-iterator function, for example:
`Lines(char[] text)` is an enumerator function. An enumerator function compiles the method's body into a state machine that manages the sequence of states the iterator function goes through while processing. That state machine is implemented as a generated class, and the state is implemented as variables within that class. That captured local state is forced from a stack context to a heap context. Since `ref struct`s like `ReadOnlySpan<T>` can't be stored in the heap, the CS4013 error is raised. To continue to use a `ReadOnlySpan<T>`, to correct this error, the method must be reimplemented as a noniterator function, for example:

```csharp
public static IEnumerable<string> Lines2(char[] text)
Expand All @@ -59,7 +61,7 @@ This enumerator method extracts lines of text from a character array. It naivel
}
```

To continue to use an iterator function, to correct this error, the method must be re-implemented to avoid using `ReadOnlySpan<T>`, for example:
To continue to use an iterator function, to correct this error, the method must be reimplemented to avoid using `ReadOnlySpan<T>`, for example:

```csharp
public static IEnumerable<string> Lines2(char[] chars)
Expand All @@ -75,3 +77,27 @@ To continue to use an iterator function, to correct this error, the method must
yield return new string(chars, startIndex, chars.Length - startIndex);
}
```

In C# 13, a `ReadOnlySpan` can be used, but can only be used in code segments without a `yield return`:

```csharp
static IEnumerable<string> Lines2(char[] text)
{
ReadOnlySpan<char> chars = text;

var lines = new List<string>();
var index = chars.IndexOf('\n');
while (index > 0)
{
lines.Add(chars[..index].ToString());
chars = chars[(index + 1)..];
index = chars.IndexOf('\n');
}

lines.Add(chars.ToString());
foreach(var line in lines)
{
yield return line;
}
}
```
6 changes: 4 additions & 2 deletions docs/csharp/language-reference/compiler-messages/cs8176.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
description: "Compiler Error CS8176"
title: "Compiler Error CS8176"
ms.date: 9/19/2022
ms.date: 06/28/2024
f1_keywords:
- "CS8176"
helpviewer_keywords:
Expand All @@ -11,7 +11,9 @@ helpviewer_keywords:

Iterators cannot have by-reference locals

Iterator blocks use deferred execution, where the evaluation of an expression is delayed until its realized value is actually required. To manage that deferred execution state, iterator blocks use a state machine, capturing variable state in closures implemented in compiler-generated classes and properties. A local variable reference (on the stack) cannot be captured within the instance of a class in the heap, so the compiler issues an error.
Iterator blocks use deferred execution, where the evaluation of an expression is delayed until its realized value is required. To manage that deferred execution state, iterator blocks use a state machine, capturing variable state in closures implemented in compiler-generated classes and properties. A local variable reference (on the stack) can't be captured within the instance of a class in the heap, so the compiler issues an error.

Beginning with C# 13, this restriction was removed.

## Example

Expand Down
8 changes: 4 additions & 4 deletions docs/csharp/language-reference/compiler-messages/cs8177.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
description: "Compiler Error CS8177"
title: "Compiler Error CS8177"
ms.date: 9/19/2022
ms.date: 7/01/2024
f1_keywords:
- "CS8177"
helpviewer_keywords:
Expand All @@ -11,11 +11,11 @@ helpviewer_keywords:

Async methods cannot have by-reference locals

To manage asynchronous state, `async` methods use a state machine, capturing variable state in closures implemented in compiler-generated classes and properties. A local variable reference (on the stack) cannot be captured within the instance of a class in the heap, so the compiler issues an error.
To manage asynchronous state, `async` methods use a state machine, capturing variable state in closures implemented in compiler-generated classes and properties. A local variable reference (on the stack) can't be captured within the instance of a class in the heap, so the compiler issues an error.

## Example

The following sample generates CS8177:
The following sample generates CS8177 before C# 13:

```csharp
// CS8177.cs (20,26)
Expand Down Expand Up @@ -49,7 +49,7 @@ class C

## To correct this error

Changing the variable declaration to remove the `ref` modifier corrects this error:
Remove the `ref` modifier. Or, you can upgrade to C# 13, which ships with .NET 9.

```csharp
class C
Expand Down
Loading
Loading