From e5e57d60c22b28bb8faac24a10572bcee4ce615a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 29 Oct 2025 19:08:06 +0000 Subject: [PATCH 1/5] Initial plan From 31ede73829485e736042d0840bd2116babc368ea Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 29 Oct 2025 19:13:28 +0000 Subject: [PATCH 2/5] Add tuples comparison and guidance to anonymous types article Co-authored-by: meaghanlewis <10103121+meaghanlewis@users.noreply.github.com> --- .../fundamentals/types/anonymous-types.md | 47 +++++++++++++++++++ .../types/snippets/anonymous-types/Program.cs | 14 ++++++ 2 files changed, 61 insertions(+) diff --git a/docs/csharp/fundamentals/types/anonymous-types.md b/docs/csharp/fundamentals/types/anonymous-types.md index 851dd8dda8d57..8df0bc4cb7ae7 100644 --- a/docs/csharp/fundamentals/types/anonymous-types.md +++ b/docs/csharp/fundamentals/types/anonymous-types.md @@ -12,6 +12,9 @@ helpviewer_keywords: 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. +> [!TIP] +> 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. + You create anonymous types by using the [`new`](../../language-reference/operators/new-operator.md) operator together with an object initializer. For more information about object initializers, see [Object and Collection Initializers](../../programming-guide/classes-and-structs/object-and-collection-initializers.md). The following example shows an anonymous type that is initialized with two properties named `Amount` and `Message`. @@ -28,6 +31,43 @@ Anonymous types are typically used in the [`select`](../../language-reference/ke Anonymous types contain one or more public read-only properties. No other kinds of class members, such as methods or events, are valid. The expression that is used to initialize a property can't be `null`, an anonymous function, or a pointer type. +## Anonymous types vs tuples + +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: + +| Feature | Anonymous types | Tuples | +|---------|----------------|--------| +| Type | Reference type (`class`) | Value type (`struct`) | +| Performance | Heap allocation | Stack allocation (better performance) | +| Mutability | Read-only properties | Mutable fields | +| Deconstruction | Not supported | Supported | +| Expression trees | Supported | Not supported | +| Access modifier | `internal` | `public` | +| Member names | Required or inferred | Optional (with default names like `Item1`, `Item2`) | + +### When to use tuples + +Use tuples when: + +- You need better performance through stack allocation. +- You want to deconstruct values into separate variables. +- You're returning multiple values from a method. +- You don't need expression tree support. + +The following example shows how tuples provide similar functionality to anonymous types with cleaner syntax: + +:::code language="csharp" source="snippets/anonymous-types/Program.cs" ID="TupleExample"::: + +### When to use anonymous types + +Use anonymous types when: + +- You're working with expression trees (for example, in some LINQ providers). +- You need the object to be a reference type. +- You're projecting query results in LINQ and want named properties without defining a class. + +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). + 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: :::code language="csharp" source="snippets/anonymous-types/Program.cs" ID="ProductDefinition"::: @@ -93,3 +133,10 @@ var v = new { Title = "Hello", Age = 24 }; Console.WriteLine(v.ToString()); // "{ Title = Hello, Age = 24 }" ``` + +## See also + +- [Tuple types](../../language-reference/builtin-types/value-tuples.md) +- [Choosing between anonymous and tuple types](../../../standard/base-types/choosing-between-anonymous-and-tuple.md) +- [Object and Collection Initializers](../../programming-guide/classes-and-structs/object-and-collection-initializers.md) +- [LINQ in C#](../../linq/index.md) diff --git a/docs/csharp/fundamentals/types/snippets/anonymous-types/Program.cs b/docs/csharp/fundamentals/types/snippets/anonymous-types/Program.cs index 8129af256fb4f..25de3800e67d0 100644 --- a/docs/csharp/fundamentals/types/snippets/anonymous-types/Program.cs +++ b/docs/csharp/fundamentals/types/snippets/anonymous-types/Program.cs @@ -78,6 +78,20 @@ from prod in products Console.WriteLine($"Title: {employee.title}, Department: {employee.department}, Salary: {employee.salary}"); // + + // + // Anonymous type example. + var anonymousProduct = new { Name = "Widget", Price = 19.99M }; + Console.WriteLine($"Anonymous: {anonymousProduct.Name} costs ${anonymousProduct.Price}"); + + // Equivalent using a tuple with named elements. + var tupleProduct = (Name: "Widget", Price: 19.99M); + Console.WriteLine($"Tuple: {tupleProduct.Name} costs ${tupleProduct.Price}"); + + // Tuples support deconstruction. + var (productName, productPrice) = tupleProduct; + Console.WriteLine($"Deconstructed: {productName} costs ${productPrice}"); + // } } } From a8c8d9f889c095470ae62203dc1bff2af22594ce Mon Sep 17 00:00:00 2001 From: Meaghan Osagie Date: Wed, 29 Oct 2025 13:36:39 -0700 Subject: [PATCH 3/5] restructure article --- .../fundamentals/types/anonymous-types.md | 26 +++++-------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/docs/csharp/fundamentals/types/anonymous-types.md b/docs/csharp/fundamentals/types/anonymous-types.md index 8df0bc4cb7ae7..5261705439b1c 100644 --- a/docs/csharp/fundamentals/types/anonymous-types.md +++ b/docs/csharp/fundamentals/types/anonymous-types.md @@ -15,22 +15,6 @@ Anonymous types provide a convenient way to encapsulate a set of read-only prope > [!TIP] > 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. -You create anonymous types by using the [`new`](../../language-reference/operators/new-operator.md) operator together with an object initializer. For more information about object initializers, see [Object and Collection Initializers](../../programming-guide/classes-and-structs/object-and-collection-initializers.md). - -The following example shows an anonymous type that is initialized with two properties named `Amount` and `Message`. - -```csharp -var v = new { Amount = 108, Message = "Hello" }; - -// Rest the mouse pointer over v.Amount and v.Message in the following -// statement to verify that their inferred types are int and string. -Console.WriteLine(v.Amount + v.Message); -``` - -Anonymous types are typically used in the [`select`](../../language-reference/keywords/select-clause.md) clause of a query expression to return a subset of the properties from each object in the source sequence. For more information about queries, see [LINQ in C#](../../linq/index.md). - -Anonymous types contain one or more public read-only properties. No other kinds of class members, such as methods or events, are valid. The expression that is used to initialize a property can't be `null`, an anonymous function, or a pointer type. - ## Anonymous types vs tuples 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: @@ -45,7 +29,7 @@ Both anonymous types and tuples let you group multiple values without defining a | Access modifier | `internal` | `public` | | Member names | Required or inferred | Optional (with default names like `Item1`, `Item2`) | -### When to use tuples +## When to use tuples Use tuples when: @@ -58,7 +42,7 @@ The following example shows how tuples provide similar functionality to anonymou :::code language="csharp" source="snippets/anonymous-types/Program.cs" ID="TupleExample"::: -### When to use anonymous types +## When to use anonymous types Use anonymous types when: @@ -72,13 +56,15 @@ The most common scenario is to initialize an anonymous type with properties from :::code language="csharp" source="snippets/anonymous-types/Program.cs" ID="ProductDefinition"::: -The anonymous type declaration starts with the `new` keyword. The declaration initializes a new type that uses only two properties from `Product`. Using anonymous types causes a smaller amount of data to be returned in the query. +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). 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. 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: :::code language="csharp" source="snippets/anonymous-types/Program.cs" ID="snippet81"::: -## Projection initializers +Anonymous types contain one or more public read-only properties. No other kinds of class members, such as methods or events, are valid. The expression that is used to initialize a property can't be `null`, an anonymous function, or a pointer type. + +## Projection initializers with anonymous 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: From 97f791d0463df7090e285382e655cd68408a152e Mon Sep 17 00:00:00 2001 From: Meaghan Osagie Date: Thu, 30 Oct 2025 10:02:38 -0700 Subject: [PATCH 4/5] Update title and TOC entry to include tuples in anonymous types documentation --- docs/csharp/fundamentals/types/anonymous-types.md | 13 ++++++------- docs/csharp/toc.yml | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/docs/csharp/fundamentals/types/anonymous-types.md b/docs/csharp/fundamentals/types/anonymous-types.md index 5261705439b1c..a2372b5165430 100644 --- a/docs/csharp/fundamentals/types/anonymous-types.md +++ b/docs/csharp/fundamentals/types/anonymous-types.md @@ -1,5 +1,5 @@ --- -title: "Anonymous Types" +title: "Anonymous Types and Tuples" 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. ms.date: 10/13/2025 f1_keywords: @@ -8,12 +8,11 @@ helpviewer_keywords: - "anonymous types [C#]" - "C# Language, anonymous types" --- -# Anonymous types +# Anonymous types and tuples 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. -> [!TIP] -> 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. +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. ## Anonymous types vs tuples @@ -58,11 +57,11 @@ The most common scenario is to initialize an anonymous type with properties from 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). -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. 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: +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. -:::code language="csharp" source="snippets/anonymous-types/Program.cs" ID="snippet81"::: +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: -Anonymous types contain one or more public read-only properties. No other kinds of class members, such as methods or events, are valid. The expression that is used to initialize a property can't be `null`, an anonymous function, or a pointer type. +:::code language="csharp" source="snippets/anonymous-types/Program.cs" ID="snippet81"::: ## Projection initializers with anonymous types diff --git a/docs/csharp/toc.yml b/docs/csharp/toc.yml index be2c11619067a..39ea2960a6c3f 100644 --- a/docs/csharp/toc.yml +++ b/docs/csharp/toc.yml @@ -56,7 +56,7 @@ items: href: fundamentals/types/interfaces.md - name: Generics href: fundamentals/types/generics.md - - name: Anonymous Types + - name: Anonymous types and tuples href: fundamentals/types/anonymous-types.md # TODO: Delegates, lambdas and events - name: Object-oriented programming From fd0ccebfb995cd4351d6912d5eda9744fde2e244 Mon Sep 17 00:00:00 2001 From: Meaghan Osagie Date: Thu, 6 Nov 2025 11:40:36 -0800 Subject: [PATCH 5/5] add more examples for tuples --- .../fundamentals/types/anonymous-types.md | 97 ++++++++++++++++--- .../types/snippets/anonymous-types/Program.cs | 4 - 2 files changed, 82 insertions(+), 19 deletions(-) diff --git a/docs/csharp/fundamentals/types/anonymous-types.md b/docs/csharp/fundamentals/types/anonymous-types.md index a2372b5165430..dece4c8c67eee 100644 --- a/docs/csharp/fundamentals/types/anonymous-types.md +++ b/docs/csharp/fundamentals/types/anonymous-types.md @@ -1,7 +1,7 @@ --- title: "Anonymous Types and Tuples" 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. -ms.date: 10/13/2025 +ms.date: 11/06/2025 f1_keywords: - "anonymousObject_CSharpKeyword" helpviewer_keywords: @@ -10,13 +10,13 @@ helpviewer_keywords: --- # Anonymous types and tuples -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. +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. 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. ## Anonymous types vs tuples -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: +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: | Feature | Anonymous types | Tuples | |---------|----------------|--------| @@ -41,29 +41,96 @@ The following example shows how tuples provide similar functionality to anonymou :::code language="csharp" source="snippets/anonymous-types/Program.cs" ID="TupleExample"::: +### Tuple deconstruction + +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: + +```csharp +// Define a method that returns a tuple +(string Name, int Age, string City) GetPersonInfo() +{ + return ("Alice", 30, "Seattle"); +} + +// Deconstruct using var for all variables +var (name, age, city) = GetPersonInfo(); +Console.WriteLine($"{name} is {age} years old and lives in {city}"); +// Output: Alice is 30 years old and lives in Seattle + +// Deconstruct with explicit types +(string personName, int personAge, string personCity) = GetPersonInfo(); +Console.WriteLine($"{personName}, {personAge}, {personCity}"); + +// Deconstruct into existing variables +string existingName; +int existingAge; +string existingCity; +(existingName, existingAge, existingCity) = GetPersonInfo(); + +// Deconstruct and discard unwanted values using the discard pattern (_) +var (name2, _, city2) = GetPersonInfo(); +Console.WriteLine($"{name2} lives in {city2}"); +// Output: Alice lives in Seattle +``` + +Deconstruction is useful in loops and pattern matching scenarios: + +```csharp +var people = new List<(string Name, int Age)> +{ + ("Bob", 25), + ("Carol", 35), + ("Dave", 40) +}; + +foreach (var (name, age) in people) +{ + Console.WriteLine($"{name} is {age} years old"); +} +``` + +### Tuples as a method return type + +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: + +```csharp +var configLookup = new Dictionary() +{ + [2] = (4, 10), + [4] = (10, 20), + [6] = (0, 23) +}; + +if (configLookup.TryGetValue(4, out (int Min, int Max) range)) +{ + Console.WriteLine($"Found range: min is {range.Min}, max is {range.Max}"); +} +// Output: Found range: min is 10, max is 20 +``` + +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. + ## When to use anonymous types Use anonymous types when: -- You're working with expression trees (for example, in some LINQ providers). +- You're working with expression trees (for example, in some Microsoft Language-Integrated Query (LINQ) providers). - You need the object to be a reference type. - You're projecting query results in LINQ and want named properties without defining a class. -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). - 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: :::code language="csharp" source="snippets/anonymous-types/Program.cs" ID="ProductDefinition"::: 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). -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. +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. -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: +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: :::code language="csharp" source="snippets/anonymous-types/Program.cs" ID="snippet81"::: -## Projection initializers with anonymous types +### Projection initializers with anonymous 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: @@ -75,7 +142,7 @@ This simplified syntax is useful when creating anonymous types with many propert The member name isn't inferred in the following cases: -- The candidate name is a duplicate of another property member in the same anonymous type, either explicit or implicit. +- The candidate name duplicates another property member in the same anonymous type, either explicit or implicit. - The candidate name isn't a valid identifier (for example, it contains spaces or special characters). In these cases, you must explicitly specify the member name. @@ -83,11 +150,11 @@ In these cases, you must explicitly specify the member name. > [!TIP] > You can use .NET style rule [IDE0037](../../../fundamentals/code-analysis/style-rules/ide0037.md) to enforce whether inferred or explicit member names are preferred. -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. +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. :::code language="csharp" source="snippets/anonymous-types/Program.cs" ID="snippet03"::: -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). +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). 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. @@ -95,11 +162,11 @@ You can create an array of anonymously typed elements by combining an implicitly var anonArray = new[] { new { name = "apple", diam = 4 }, new { name = "grape", diam = 1 }}; ``` -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. +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. 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. -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: +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: :::code language="csharp" source="snippets/anonymous-types/Program.cs" ID="snippet02"::: @@ -109,7 +176,7 @@ Because the and [!NOTE] > 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. -> Therefore instances of anonymous types can't be equal to each other when defined in different assemblies, even when having all their properties equal. +> Therefore, instances of anonymous types can't be equal to each other when defined in different assemblies, even when having all their properties equal. Anonymous types do override the method, concatenating the name and `ToString` output of every property surrounded by curly braces. diff --git a/docs/csharp/fundamentals/types/snippets/anonymous-types/Program.cs b/docs/csharp/fundamentals/types/snippets/anonymous-types/Program.cs index 25de3800e67d0..a713f20dde1dd 100644 --- a/docs/csharp/fundamentals/types/snippets/anonymous-types/Program.cs +++ b/docs/csharp/fundamentals/types/snippets/anonymous-types/Program.cs @@ -87,10 +87,6 @@ from prod in products // Equivalent using a tuple with named elements. var tupleProduct = (Name: "Widget", Price: 19.99M); Console.WriteLine($"Tuple: {tupleProduct.Name} costs ${tupleProduct.Price}"); - - // Tuples support deconstruction. - var (productName, productPrice) = tupleProduct; - Console.WriteLine($"Deconstructed: {productName} costs ${productPrice}"); // } }