How to Project Anonymous Types in C# LINQ
Projecting anonymous types in C# LINQ enables developers to transform
query results into lightweight, read-only objects without explicitly
defining a class or struct. This article explains how to use the LINQ
select clause to construct anonymous types using both query
and method syntax, assign custom property names, and handle common
limitations.
What Is an Anonymous Type Projection?
An anonymous type projection uses the new keyword
followed by an object initializer within a LINQ select
clause. The C# compiler automatically generates an immutable class
containing read-only properties inferred from your assignment.
Query Syntax
In LINQ query syntax, place the new { ... } expression
directly inside the select clause at the end of your
query.
var employees = new List<Employee>
{
new Employee { Id = 1, FirstName = "Jane", LastName = "Doe", Salary = 85000, Department = "IT" },
new Employee { Id = 2, FirstName = "John", LastName = "Smith", Salary = 60000, Department = "HR" }
};
var query = from e in employees
where e.Salary > 70000
select new
{
FullName = e.FirstName + " " + e.LastName,
e.Department
};
foreach (var item in query)
{
Console.WriteLine($"{item.FullName} works in {item.Department}");
}Method Syntax
In method syntax, supply a lambda expression returning the anonymous
type directly into the Select() extension method.
var result = employees
.Where(e => e.Salary > 70000)
.Select(e => new
{
FullName = $"{e.FirstName} {e.LastName}",
e.Department
});Property Name Rules
When projecting anonymous types, property names can be inferred or explicitly assigned:
Inferred Names: If you pass an existing member without assigning a name, the compiler uses the existing member's name (projection initializers).
select new { e.FirstName, e.Department } // Results in properties: item.FirstName, item.DepartmentExplicit Names: If you perform a transformation, calculation, or want a different property name, you must explicitly assign it.
select new { DisplayName = e.FirstName, AnnualComp = e.Salary } // Results in properties: item.DisplayName, item.AnnualComp
Working with Nested Anonymous Types
You can nest anonymous types within each other to represent hierarchical data structures.
var nestedResult = employees.Select(e => new
{
e.Id,
Details = new
{
e.FirstName,
e.LastName
},
Compensation = new
{
e.Salary,
Bonus = e.Salary * 0.10m
}
});Key Considerations and Limitations
- Immutability: Properties on anonymous types are read-only and cannot be modified after instantiation.
- Scope: Anonymous types are designed for local use
within the method they are declared in. They cannot be used as method
return types or parameters without boxing them to
objector usingdynamic, which loses compile-time type safety. - Alternative for Method Returns: If you need to pass
projected data outside the declaring method, use C# 7+ value tuples
(
(string Name, decimal Salary)) or C# 9+recordtypes instead of anonymous types.