|
| 1 | +--- |
| 2 | +title: Deconstructing tuples and other types | Microsoft Docs |
| 3 | +description: Learn how to deconstruct tuples and other types |
| 4 | +keywords: .NET, .NET Core, C#0 |
| 5 | +author: rpetrusha |
| 6 | +ms-author: ronpet |
| 7 | +ms.date: 07/18/2016 |
| 8 | +ms.topic: article |
| 9 | +ms.prod: .net |
| 10 | +ms.technology: devlang-csharp |
| 11 | +ms.devlang: csharp |
| 12 | +ms.assetid: 0b0c4b0f-4a47-4f66-9b8e-f5c63b195960 |
| 13 | +--- |
| 14 | + |
| 15 | +# Deconstructing tuples and other types # |
| 16 | + |
| 17 | +A tuple provides a light-weight way to retrieve multiple values from a method call. But once you retrieve the tuple, you have to handle its individual elements. Doing this on an element-by-element basis is cumbersome, as the following example shows. The `QueryCityData` method returns a 3-tuple, and each of its elements is assigned to a variable in a separate operation. |
| 18 | + |
| 19 | +[!code-csharp[WithoutDeconstruction](../../samples/snippets/csharp/programming-guide/deconstructing-tuples/deconstruct-tuple1.cs)] |
| 20 | + |
| 21 | +Retrieving multiple field and property values from an object can be equally cumbersome: you have to assign a field or property value to a variable on a member-by-member basis. |
| 22 | + |
| 23 | +Starting with C# 7, you can retrieve multiple elements from a tuple or retrieve multiple field, property, and computed values from an object in a single *deconstruct* operation. When you deconstruct a tuple, you assign its elements to individual variables. When you deconstruct an object, you assign selected values to individual variables. |
| 24 | + |
| 25 | +## Deconstructing a tuple |
| 26 | + |
| 27 | +C# features built-in support for deconstructing tuples, which lets you unpackage all the items in a tuple in a single operation. The general syntax for deconstructing a tuple is similar to the syntax for defining one: you enclose the variables to which each element is to be assigned in parentheses in the left side of an assignment statement. For example, the following statement assigns the elements of a 4-tuple to four separate variables: |
| 28 | + |
| 29 | +```csharp |
| 30 | +var (name, address, city, zip) = contact.GetAddressInfo(); |
| 31 | +``` |
| 32 | + |
| 33 | +There are two ways to deconstruct a tuple: |
| 34 | + |
| 35 | +- You can explicitly declare the type of each field inside parentheses. The following example uses this approach to deconstruct the 3-tuple returned by the `QueryCityData` method. |
| 36 | + |
| 37 | + [!code-csharp[Deconstruction-Explicit](../../samples/snippets/csharp/programming-guide/deconstructing-tuples/deconstruct-tuple2.cs#1)] |
| 38 | + |
| 39 | +- You can use the `var` keyword so that C# infers the type of each variable. You place the `var` keyword outside of the parentheses. The following example uses type inference when deconstructing the 3-tuple returned by the `QueryCityData` method. |
| 40 | + |
| 41 | + [!code-csharp[Deconstruction-Infer](../../samples/snippets/csharp/programming-guide/deconstructing-tuples/deconstruct-tuple3.cs#1)] |
| 42 | + |
| 43 | + You can also use the `var` keyword individually with any or all of the variable declarations inside the parentheses. |
| 44 | + |
| 45 | + [!code-csharp[Deconstruction-Infer-Some](../../samples/snippets/csharp/programming-guide/deconstructing-tuples/deconstruct-tuple4.cs#1)] |
| 46 | + |
| 47 | + This is cumbersome and is not recommended. |
| 48 | + |
| 49 | +Note that you cannot specify a specific type outside the parentheses even if every field in the tuple has the |
| 50 | +same type. This generates compiler error CS8136, "`var (...)` form disallows a specific type for `var`. |
| 51 | + |
| 52 | +Note that you must also assign each element of the tuple to a variable. If you omit any elements, the compiler generates error CS8132, "Cannot deconstruct a tuple of 'x' elements into 'y' variables." |
| 53 | + |
| 54 | +## Deconstructing tuple elements with discards |
| 55 | + |
| 56 | +Often when deconstructing a tuple, you're interested in the values of only some elements. Starting with C# 7, you can take advantage of C#'s support for *discards*, which are write-only variables whose values you've chosen to ignore. A discard is designated by an underscore character ("_") in an assignment. You can discard as many values as you like; all are represented by the single discard, `_`. |
| 57 | + |
| 58 | +The following example illustrates the use of tuples with discards. The `QueryCityDataForYears` method returns a 6-tuple with the name of a city, its area, a year, the city's population for that year, a second year, and the city's population for that second year. The example shows the change in population between those two years. Of the data available from the tuple, we're unconcerned with the city area, and we know the city name and the two dates at design-time. As a result, we're only interested in the two population values stored in the tuple, and can handle its remaining values as discards. |
| 59 | + |
| 60 | +[!code-csharp[Tuple-discard](../../samples/snippets/csharp/programming-guide/deconstructing-tuples/discard-tuple1.cs)] |
| 61 | + |
| 62 | +### Deconstructing user-defined types |
| 63 | + |
| 64 | +Non-tuple types do not offer built-in support for discards. However, as the author of a class, a struct, or an interface, you can allow instances of the type to be deconstructed by implementing one or more `Deconstruct` methods. The method returns void, and each value to be deconstructed is indicated by an [out](language-reference/keywords/out-parameter-modifier.md) parameter in the method signature. For example, the following `Deconstruct` method of a `Person` class returns the first, middle, and last name: |
| 65 | + |
| 66 | +[!code-csharp[Class-deconstruct](../../samples/snippets/csharp/programming-guide/deconstructing-tuples/deconstruct-class1.cs#1)] |
| 67 | + |
| 68 | +You can then deconstruct an instance of the `Person` class named `p` with an assignment like the following: |
| 69 | + |
| 70 | +[!code-csharp[Class-deconstruct](../../samples/snippets/csharp/programming-guide/deconstructing-tuples/deconstruct-class1.cs#2)] |
| 71 | + |
| 72 | +The following example overloads the `Deconstruct` method to return various combinations of properties of a `Person` object. Individual overloads return: |
| 73 | + |
| 74 | +- A first and last name. |
| 75 | +- A first, last, and middle name. |
| 76 | +- A first name, a last name, a city name, and a state name. |
| 77 | + |
| 78 | +[!code-csharp[Class-deconstruct](../../samples/snippets/csharp/programming-guide/deconstructing-tuples/deconstruct-class2.cs)] |
| 79 | + |
| 80 | +Because you can overload the `Deconstruct` method to reflect groups of data that are commonly extracted from an object, you should be careful to define `Deconstruct` methods with signatures that are distinctive and unambiguous. Multiple `Deconstruct` methods that have the same number of `out` parameters or the same number and type of `out` parameters in a different order can cause confusion. |
| 81 | + |
| 82 | +The overloaded `Deconstruct` method in the following example illustrates one possible source of confusion. The first overload returns the first name, middle name, last name, and age of a `Person` object, in that order. The second overload returns name information only along with annual income, but the first, middle, and last name are in a different order. This makes it easy to confuse the order of arguments when deconstructing a `Person` instance. |
| 83 | + |
| 84 | +[!code-csharp[Deconstruct-ambiguity](../../samples/snippets/csharp/programming-guide/deconstructing-tuples/deconstruct-ambiguous.cs)] |
| 85 | + |
| 86 | +## Deconstructing a user-defined type with discards |
| 87 | + |
| 88 | +Just as you do with [tuples](#deconstructing-tuple-elements-with-discards), you can use discards to ignore selected items returned by a `Deconstruct` method. Each discard is defined by a variable named "_", and a single deconstruction operation can include multiple discards. |
| 89 | + |
| 90 | +The following example deconstructs a `Person` object into four strings (the first and last names, the city, and the state) but discards the last name and the state. |
| 91 | + |
| 92 | +[!code-csharp[Class-discard](../../samples/snippets/csharp/programming-guide/deconstructing-tuples/class-discard1.cs#1)] |
| 93 | + |
| 94 | +## Deconstructing a user-defined type with an extension method |
| 95 | + |
| 96 | +If you didn't author a class, struct, or interface, you can still deconstruct objects of that type by implementing one or more `Deconstruct` [extension methods](programming-guide/classes-and-structs/extension-methods.md) to return the values in which you're interested. |
| 97 | + |
| 98 | +The following example defines two `Deconstruct` extension methods for the <xref:System.Reflection.PropertyInfo?displayProperty=fullName> class. The first returns a set of values that indicate the characteristics of the property, including its type, whether it's static or instance, whether it's read-only, and whether it's indexed. The second indicates the property's accessibility. Because the accessibility of get and set accessors can differ, Boolean values indicate whether the property has separate get and set accessors and, if it does, whether they have the same accessibility. If there is only one accessor or both the get and the set accessor have the same accessibility, the `access` variable indicates the accessibility of the property as a whole. Otherwise, the accessibility of the get and set accessors are indicated by the accessaccessibility is indicated by the `getAccess` and `setAccess` variables. |
| 99 | + |
| 100 | +[!code-csharp[Extension-deconstruct](../../samples/snippets/csharp/programming-guide/deconstructing-tuples/deconstruct-extension1.cs)] |
| 101 | + |
| 102 | +## See also |
| 103 | +[Discards](discards.md) |
| 104 | +[Tuples](tuples.md) |
0 commit comments