You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/csharp/fundamentals/types/anonymous-types.md
+82-15Lines changed: 82 additions & 15 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,7 +1,7 @@
1
1
---
2
2
title: "Anonymous Types and Tuples"
3
3
description: Anonymous types in C# encapsulate a set of read-only properties in an object without having to explicitly define a type. The compiler generates a name.
4
-
ms.date: 10/13/2025
4
+
ms.date: 11/06/2025
5
5
f1_keywords:
6
6
- "anonymousObject_CSharpKeyword"
7
7
helpviewer_keywords:
@@ -10,13 +10,13 @@ helpviewer_keywords:
10
10
---
11
11
# Anonymous types and tuples
12
12
13
-
Anonymous types provide a convenient way to encapsulate a set of read-only properties into a single object without having to explicitly define a type first. The type name is generated by the compiler and isn't available at the source code level. The type of each property is inferred by the compiler.
13
+
Anonymous types provide a convenient way to encapsulate a set of read-only properties into a single object without having to explicitly define a type first. The compiler generates the type name, and it's not available at the source code level. The compiler infers the type of each property.
14
14
15
15
In most scenarios, [tuples](../../language-reference/builtin-types/value-tuples.md) are the preferred choice over anonymous types. Tuples provide better performance, support deconstruction, and offer more flexible syntax. Use anonymous types primarily when you need expression tree support or when working with code that requires reference types.
16
16
17
17
## Anonymous types vs tuples
18
18
19
-
Both anonymous types and tuples let you group multiple values without defining a named type. However, tuples are the preferred choice in most scenarios because they provide better performance and more flexibility. The following table summarizes the key differences:
19
+
Both anonymous types and tuples let you group multiple values without defining a named type. However, tuples have better language support and compile to a more efficient data structure. The following table summarizes the key differences:
20
20
21
21
| Feature | Anonymous types | Tuples |
22
22
|---------|----------------|--------|
@@ -41,29 +41,96 @@ The following example shows how tuples provide similar functionality to anonymou
You can deconstruct a tuple into separate variables, which provides a convenient way to work with individual tuple elements. C# supports several ways to deconstruct tuples:
47
+
48
+
```csharp
49
+
// Define a method that returns a tuple
50
+
(stringName, intAge, stringCity) GetPersonInfo()
51
+
{
52
+
return ("Alice", 30, "Seattle");
53
+
}
54
+
55
+
// Deconstruct using var for all variables
56
+
var (name, age, city) =GetPersonInfo();
57
+
Console.WriteLine($"{name} is {age} years old and lives in {city}");
58
+
// Output: Alice is 30 years old and lives in Seattle
// Deconstruct and discard unwanted values using the discard pattern (_)
71
+
var (name2, _, city2) =GetPersonInfo();
72
+
Console.WriteLine($"{name2} lives in {city2}");
73
+
// Output: Alice lives in Seattle
74
+
```
75
+
76
+
Deconstruction is useful in loops and pattern matching scenarios:
77
+
78
+
```csharp
79
+
varpeople=newList<(stringName, intAge)>
80
+
{
81
+
("Bob", 25),
82
+
("Carol", 35),
83
+
("Dave", 40)
84
+
};
85
+
86
+
foreach (var (name, age) inpeople)
87
+
{
88
+
Console.WriteLine($"{name} is {age} years old");
89
+
}
90
+
```
91
+
92
+
### Tuples as a method return type
93
+
94
+
A common use case for tuples is as a method return type. Instead of defining `out` parameters, you can group method results in a tuple. The following example demonstrates using tuples with dictionary lookups to return configuration ranges:
if (configLookup.TryGetValue(4, out (intMin, intMax) range))
105
+
{
106
+
Console.WriteLine($"Found range: min is {range.Min}, max is {range.Max}");
107
+
}
108
+
// Output: Found range: min is 10, max is 20
109
+
```
110
+
111
+
This pattern is useful when working with methods that need to return both a success indicator and multiple result values. The tuple allows you to use named fields (`Min` and `Max`) instead of generic names like `Item1` and `Item2`, making the code more readable and self-documenting.
112
+
44
113
## When to use anonymous types
45
114
46
115
Use anonymous types when:
47
116
48
-
- You're working with expression trees (for example, in some LINQ providers).
117
+
- You're working with expression trees (for example, in some Microsoft Language-Integrated Query (LINQ) providers).
49
118
- You need the object to be a reference type.
50
119
- You're projecting query results in LINQ and want named properties without defining a class.
51
120
52
-
For more information about choosing between anonymous types and tuples, see [Choosing between anonymous and tuple types](../../../standard/base-types/choosing-between-anonymous-and-tuple.md).
53
-
54
121
The most common scenario is to initialize an anonymous type with properties from another type. In the following example, assume that a class exists that is named `Product`. Class `Product` includes `Color` and `Price` properties, together with other properties that you aren't interested in:
The anonymous type declaration starts with the [`new`](../../language-reference/operators/new-operator.md) operator together with an [object initializer](../../programming-guide/classes-and-structs/object-and-collection-initializers.md). The declaration initializes a new type that uses only two properties from `Product`. Anonymous types are typically used in the [`select`](../../language-reference/keywords/select-clause.md) clause of a query expression to return a smaller amount of data. For more information about queries, see [LINQ in C#](../../linq/index.md).
59
126
60
-
If you don't specify member names in the anonymous type, the compiler gives the anonymous type members the same name as the property being used to initialize them. You provide a name for a property that's being initialized with an expression, as shown in the previous example.
127
+
If you don't specify member names in the anonymous type, the compiler gives the anonymous type members the same name as the property used to initialize them. You provide a name for a property that's being initialized with an expression, as shown in the previous example.
61
128
62
-
In the following example, the names of the properties of the anonymous type are `Color` and `Price`. The instances are item from the `products` collection of `Product` types:
129
+
In the following example, the names of the properties of the anonymous type are `Color` and `Price`. The instances are items from the `products` collection of `Product` types:
Anonymous types support *projection initializers*, which allow you to use local variables or parameters directly without explicitly specifying the member name. The compiler infers the member names from the variable names. The following example demonstrates this simplified syntax:
69
136
@@ -75,31 +142,31 @@ This simplified syntax is useful when creating anonymous types with many propert
75
142
76
143
The member name isn't inferred in the following cases:
77
144
78
-
- The candidate name is a duplicate of another property member in the same anonymous type, either explicit or implicit.
145
+
- The candidate name duplicates another property member in the same anonymous type, either explicit or implicit.
79
146
- The candidate name isn't a valid identifier (for example, it contains spaces or special characters).
80
147
81
148
In these cases, you must explicitly specify the member name.
82
149
83
150
> [!TIP]
84
151
> You can use .NET style rule [IDE0037](../../../fundamentals/code-analysis/style-rules/ide0037.md) to enforce whether inferred or explicit member names are preferred.
85
152
86
-
It's also possible to define a field by object of another type: class, struct, or even another anonymous type. It's done by using the variable holding this object just like in the following example, where two anonymous types are created using already instantiated user-defined types. In both cases, the `product` field in the anonymous type`shipment` and `shipmentWithBonus` is of type `Product`containing its default values of each field. And the `bonus` field is of anonymous type created by the compiler.
153
+
You can also define a field by using an object of another type: class, struct, or even another anonymous type. To do this, use the variable that holds this object. The following example shows two anonymous types that use already instantiated user-defined types. In both cases, the `product` field in the anonymous types`shipment` and `shipmentWithBonus` is of type `Product`and contains the default values of each field. The `bonus` field is of an anonymous type created by the compiler.
Typically, when you use an anonymous type to initialize a variable, you declare the variable as an implicitly typed local variable by using [var](../../language-reference/statements/declarations.md#implicitly-typed-local-variables). The type name can't be specified in the variable declaration because only the compiler has access to the underlying name of the anonymous type. For more information about `var`, see [Implicitly Typed Local Variables](../../programming-guide/classes-and-structs/implicitly-typed-local-variables.md).
157
+
Typically, when you use an anonymous type to initialize a variable, you declare the variable as an implicitly typed local variable by using [var](../../language-reference/statements/declarations.md#implicitly-typed-local-variables). You can't specify the type name in the variable declaration because only the compiler has access to the underlying name of the anonymous type. For more information about `var`, see [Implicitly Typed Local Variables](../../programming-guide/classes-and-structs/implicitly-typed-local-variables.md).
91
158
92
159
You can create an array of anonymously typed elements by combining an implicitly typed local variable and an implicitly typed array, as shown in the following example.
93
160
94
161
```csharp
95
162
varanonArray=new[] { new { name="apple", diam=4 }, new { name="grape", diam=1 }};
96
163
```
97
164
98
-
Anonymous types are [`class`](../../language-reference/keywords/class.md) types that derive directly from [`object`](../../language-reference/builtin-types/reference-types.md), and that can't be cast to any type except [`object`](../../language-reference/builtin-types/reference-types.md). The compiler provides a name for each anonymous type, although your application can't access it. From the perspective of the common language runtime, an anonymous type is no different from any other reference type.
165
+
Anonymous types are [`class`](../../language-reference/keywords/class.md) types that derive directly from [`object`](../../language-reference/builtin-types/reference-types.md), and you can't cast them to any type except [`object`](../../language-reference/builtin-types/reference-types.md). The compiler provides a name for each anonymous type, although your application can't access it. From the perspective of the common language runtime, an anonymous type is no different from any other reference type.
99
166
100
167
If two or more anonymous object initializers in an assembly specify a sequence of properties that are in the same order and that have the same names and types, the compiler treats the objects as instances of the same type. They share the same compiler-generated type information.
101
168
102
-
Anonymous types support non-destructive mutation in the form of [with expressions](../../language-reference/operators/with-expression.md). This enables you to create a new instance of an anonymous type where one or more properties have new values:
169
+
Anonymous types support non-destructive mutation in the form of [with expressions](../../language-reference/operators/with-expression.md). This feature enables you to create a new instance of an anonymous type where one or more properties have new values:
@@ -109,7 +176,7 @@ Because the <xref:System.Object.Equals%2A> and <xref:System.Object.GetHashCode%2
109
176
110
177
> [!NOTE]
111
178
> The [accessibility level](../../programming-guide/classes-and-structs/access-modifiers.md) of an anonymous type is `internal`. Hence, two anonymous types defined in different assemblies aren't of the same type.
112
-
> Therefore instances of anonymous types can't be equal to each other when defined in different assemblies, even when having all their properties equal.
179
+
> Therefore, instances of anonymous types can't be equal to each other when defined in different assemblies, even when having all their properties equal.
113
180
114
181
Anonymous types do override the <xref:System.Object.ToString%2A> method, concatenating the name and `ToString` output of every property surrounded by curly braces.
0 commit comments