-
Notifications
You must be signed in to change notification settings - Fork 6.1k
Add deconstruction lang reference #44023
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 3 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
be7252b
Add deconstruction lang reference
BillWagner a05ea3a
fix build issue
BillWagner e499e84
proofread and edit
BillWagner d48d407
Update docs/csharp/language-reference/tokens/discard.md
BillWagner 184e4e1
Apply suggestions from code review
BillWagner File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
61 changes: 61 additions & 0 deletions
61
docs/csharp/language-reference/operators/deconstruction.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| --- | ||
| title: "Deconstruction expression - extract properties or fields from a tuple or other type" | ||
| description: "Learn about deconstruction expressions: expressions that extract individual properties or fields from a tuple or user defined type into discrete expressions." | ||
| ms.date: 12/17/2024 | ||
| --- | ||
| # Deconstruction expression - Extract properties of fields from a tuple or other user defined type | ||
|
|
||
| A *deconstruction expression* extracts data fields from an instance of an object. Each discrete data element is written to a distinct variable, as shown in the following example: | ||
|
|
||
| :::code language="csharp" source="./snippets/shared/Deconstruction.cs" id="TupleDeconstruction"::: | ||
|
|
||
| The preceding code snippet creates a [tuple](../builtin-types/value-tuples.md) that has two integer values, `X` and `Y`. The second statement *deconstructs* that tuple and stores the tuple elements in discrete variables `x`, and `y`. | ||
BillWagner marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ## Tuple deconstruction | ||
|
|
||
| All [tuple types](../builtin-types/value-tuples.md) support deconstruction expressions. Tuple deconstruction extracts all the tuple's elements. If you only want some of the tuple elements, use a [discard](../tokens/discard.md) for the unused tuple members, as shown in the following example: | ||
|
|
||
| :::code language="csharp" source="./snippets/shared/Deconstruction.cs" id="TupleDeconstructionWithDiscard"::: | ||
|
|
||
| In the preceding example, the `Y` and `label` members are discarded. You can specify multiple discards in the same deconstruction expression. You can use discards for all the members of the tuple. The following example is legal, although not useful: | ||
|
|
||
| :::code language="csharp" source="./snippets/shared/Deconstruction.cs" id="AllDiscards"::: | ||
|
|
||
| ## Record deconstruction | ||
|
|
||
| [Record](../builtin-types/record.md) types that have a [primary constructor](../builtin-types/record.md#positional-syntax-for-property-definition) support deconstruction for positional parameters. The compiler synthesizes a `Deconstruct` method that extracts the properties synthesized from positional parameters in the primary constructor. The compiler synthesized `Deconstruction` method doesn't extract properties declared as properties in the record type. | ||
BillWagner marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| The `record` shown in the following code declares two positional properties, `SquareFeet` and `Address`, along with another property, `RealtorNotes`: | ||
|
|
||
| :::code language="csharp" source="./snippets/shared/Deconstruction.cs" id="RecordDeconstruction"::: | ||
|
|
||
| When you deconstruct a `House` object, all positional properties, and only positional properties, are deconstructed, as shown in the following example: | ||
|
|
||
| :::code language="csharp" source="./snippets/shared/Deconstruction.cs" id="RecordDeconstructionUsage"::: | ||
|
|
||
| You can make use of this behavior to specify which properties of your record types are part of the compiler synthesized `Deconstruct` method. | ||
BillWagner marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ## Declare `Deconstruct` methods | ||
|
|
||
| You can add deconstruction support to any class, struct, or interface you declare. You declare one or `Deconstruct` methods in your type, or as extension methods on that type. A deconstruction expression calls a method `void Deconstruct(out var p1, ..., out var pn)`. The `Deconstruct` method can be either an instance method or an extension method. The type of each parameter in the `Deconstruct` method must match the type of the corresponding argument in the deconstruction expression. The deconstruction expression assigns the value of each argument to the value of the corresponding `out` parameter in the `Deconstruct` method. If multiple `Deconstruct` methods match the deconstruction expression, the compiler reports an error for the ambiguity. | ||
|
|
||
| The following code declares a `Point3D` struct that has two `Deconstruct` methods: | ||
|
|
||
| :::code language="csharp" source="./snippets/shared/Deconstruction.cs" id="StructDeconstruction"::: | ||
|
|
||
| The first method supports deconstruction expressions that extract all three axes values: `X`, `Y`, and `Z`. The second method supports deconstructing only the planar values: `X` and `Y`. The first method has an *arity* of 3; the second has an arity of 2. | ||
BillWagner marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| The preceding section described the compiler synthesized `Deconstruct` method for `record` types with a primary constructor. You can declare more `Deconstruct` methods in record types. These methods can either add other properties, remove some of the default properties, or both. You can also declare a `Deconstruct` that matches the compiler synthesized signature. If you declare such a `Deconstruct` method, the compiler doesn't synthesize one. | ||
BillWagner marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| Typically, multiple `Deconstruct` methods for the same type have different numbers of parameters. You can create multiple `Deconstruct` methods providing the signatures have different parameter types. As long as the compiler can determine one unique `Deconstruct` method for a deconstruction expression, the multiple `Deconstruct` methods are allowed. However, in many cases, too many `Deconstruct` methods can lead to ambiguity errors and misleading results. | ||
BillWagner marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ## C# language specification | ||
|
|
||
| For more information, see the following sections of the [C# Standard](~/_csharpstandard/standard/expressions.md#127-deconstruction): | ||
BillWagner marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ## See also | ||
|
|
||
| - [C# operators and expressions](index.md) | ||
| - [Tuple types](../builtin-types/value-tuples.md) | ||
| - [Records](../builtin-types/record.md) | ||
| - [Structure types](../builtin-types/struct.md) | ||
88 changes: 88 additions & 0 deletions
88
docs/csharp/language-reference/operators/snippets/shared/Deconstruction.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Linq; | ||
| using System.Reflection.Emit; | ||
| using System.Text; | ||
| using System.Threading.Tasks; | ||
|
|
||
| namespace operators; | ||
| public class Deconstruction | ||
| { | ||
| public static void Examples() | ||
| { | ||
| // <TupleDeconstruction> | ||
| var tuple = (X: 1, Y: 2); | ||
| var (x, y) = tuple; | ||
|
|
||
| Console.WriteLine(x); // output: 1 | ||
| Console.WriteLine(y); // output: 2 | ||
| // </TupleDeconstruction> | ||
|
|
||
| // <TupleDeconstructionWithDiscard> | ||
| var tuple2 = (X: 0, Y: 1, Label: "The origin"); | ||
| var (x2, _, _) = tuple2; | ||
| // </TupleDeconstructionWithDiscard> | ||
|
|
||
| // <AllDiscards> | ||
| var (_, _, _) = tuple2; | ||
| // </AllDiscards> | ||
|
|
||
| // <RecordDeconstructionUsage> | ||
| var house = new House(1000, "123 Coder St.") | ||
| { | ||
| RealtorNotes = """ | ||
| This is a great starter home, with a separate room that's a great home office setup. | ||
| """ | ||
| }; | ||
|
|
||
| var (squareFeet, address) = house; | ||
| Console.WriteLine(squareFeet); // output: 1000 | ||
| Console.WriteLine(address); // output: 123 Coder St. | ||
| Console.WriteLine(house.RealtorNotes); | ||
| // </RecordDeconstructionUsage> | ||
|
|
||
| // <StructDeconstructionUsage> | ||
| var point = new Point3D { X = 1, Y = 2, Z = 3 }; | ||
|
|
||
| // Deconstruct 3D coords | ||
| var (x3, y3, z3) = point; | ||
| Console.WriteLine(x3); // output: 1 | ||
| Console.WriteLine(y3); // output: 2 | ||
| Console.WriteLine(z3); // output: 3 | ||
|
|
||
| // Deconstruct 2D coords | ||
| var (x4, y4) = point; | ||
| Console.WriteLine(x4); // output: 1 | ||
| Console.WriteLine(y4); // output: 2 | ||
| // </StructDeconstructionUsage> | ||
| } | ||
| } | ||
|
|
||
| // <RecordDeconstruction> | ||
| public record House(int SquareFeet, string Address) | ||
| { | ||
| public required string RealtorNotes { get; set; } | ||
| } | ||
| // </RecordDeconstruction> | ||
|
|
||
| // <StructDeconstruction> | ||
| public struct Point3D | ||
| { | ||
| public int X { get; set; } | ||
| public int Y { get; set; } | ||
| public int Z { get; set; } | ||
|
|
||
| public void Deconstruct(out int x, out int y, out int z) | ||
| { | ||
| x = X; | ||
| y = Y; | ||
| z = Z; | ||
| } | ||
|
|
||
| public void Deconstruct(out int x, out int y) | ||
| { | ||
| x = X; | ||
| y = Y; | ||
| } | ||
| } | ||
| // </StructDeconstruction> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| --- | ||
| description: "A `_` is a discard, a placeholder for an unused variable in an expression" | ||
| title: "Discard - _" | ||
| ms.date: 12/17/2024 | ||
| --- | ||
| # Discard - A `_` acts as a placeholder for a variable | ||
|
|
||
| The `_` character services as a *discard*, which is a placeholder for an unused variable. | ||
BillWagner marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| There are two uses for the *discard* token: | ||
|
|
||
| 1. To declare an unused variable. A discard can't be read or accessed. | ||
| - Unused `out` arguments: `var r = M(out int _, out var _, out _);` | ||
| - Unused lambda expression parameters: `Action<int> _ => WriteMessage();` | ||
| - Unused deconstruction arguments: `(int _, var answer) = M();` | ||
| 1. To match any expression in a [discard pattern](../operators/patterns.md#discard-pattern). You can add a `_` pattern to satisfy exhaustiveness requirements. | ||
|
|
||
| The `_` token is a valid identifier in C#. The `_` token is interpreted as a discard only when no valid identifier named `_` is found in scope. | ||
|
|
||
| A discard can't be read as a variable. The compiler reports an error if your code reads a discard. The compiler can avoid allocating the storage for a discard in some situations where that is safe. | ||
|
|
||
| ## See also | ||
|
|
||
| - [Tuples](../builtin-types/value-tuples.md) | ||
| - [Deconstruction](../tokens/discard.md) | ||
| - [Discard pattern](../operators/patterns.md#discard-pattern) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.