diff --git a/docs/csharp/fundamentals/types/anonymous-types.md b/docs/csharp/fundamentals/types/anonymous-types.md index d86d624246787..14ff13c4f8a6e 100644 --- a/docs/csharp/fundamentals/types/anonymous-types.md +++ b/docs/csharp/fundamentals/types/anonymous-types.md @@ -38,6 +38,24 @@ If you don't specify member names in the anonymous type, the compiler gives the :::code language="csharp" source="snippets/anonymous-types/Program.cs" ID="snippet81"::: +## Projection initializers + +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: + +:::code language="csharp" source="snippets/anonymous-types/Program.cs" ID="ProjectionInitializers"::: + +This simplified syntax is particularly useful when creating anonymous types with many properties: + +:::code language="csharp" source="snippets/anonymous-types/Program.cs" ID="ProjectionExample"::: + +The member name isn't inferred in the following cases: + +- The candidate name is a member name of an anonymous type, such as `ToString` or `GetHashCode`. +- The candidate name is a duplicate of 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. + > [!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. diff --git a/docs/csharp/fundamentals/types/snippets/anonymous-types/Program.cs b/docs/csharp/fundamentals/types/snippets/anonymous-types/Program.cs index 2b64b2cb05cda..4b665a0007a5b 100644 --- a/docs/csharp/fundamentals/types/snippets/anonymous-types/Program.cs +++ b/docs/csharp/fundamentals/types/snippets/anonymous-types/Program.cs @@ -18,9 +18,9 @@ class Anonymous { static void Main() { - // don't show this unless you add a bunch more - // properties to the type. otherwise it obviates the - // need for the anonymous type + // Don't show this unless you add a bunch more + // properties to the type. Otherwise it obviates the + // need for the anonymous type. List products = new () { new Product() { Color="Orange", Price=2.00M}, @@ -50,6 +50,34 @@ from prod in products var shipment = new { address = "Nowhere St.", product }; var shipmentWithBonus = new { address = "Somewhere St.", product, bonus }; // + + // + // Explicit member names. + var personExplicit = new { FirstName = "Kyle", LastName = "Mit" }; + + // Projection initializers (inferred member names). + var firstName = "Kyle"; + var lastName = "Mit"; + var personInferred = new { firstName, lastName }; + + // Both create equivalent anonymous types with the same property names. + Console.WriteLine($"Explicit: {personExplicit.FirstName} {personExplicit.LastName}"); + Console.WriteLine($"Inferred: {personInferred.firstName} {personInferred.lastName}"); + // + + // + var title = "Software Engineer"; + var department = "Engineering"; + var salary = 75000; + + // Using projection initializers. + var employee = new { title, department, salary }; + + // Equivalent to explicit syntax: + // var employee = new { title = title, department = department, salary = salary }; + + Console.WriteLine($"Title: {employee.title}, Department: {employee.department}, Salary: {employee.salary}"); + // } } }