Anonymous types arrived in C# 3.0 to support LINQ projections. Instead of creating a named class every time you need to reshape data, you write new { Name = x.Name, Count = x.Items.Count } and let the compiler build a class for you.
Why it matters
Powers LINQ projections. When you select a subset of fields from a LINQ query, anonymous types let you skip the ceremony of creating DTOs for every shape your code needs.
Enables rapid prototyping. In exploratory code or when experimenting with data shapes, anonymous types let you iterate without defining a catalog of classes. This is especially valuable in scripts, utilities, and interactive work.
Pairs naturally with var. You declare var result = new { ... } and the compiler infers the type. This reads well and keeps focus on the data, not the type declaration.
Equality “just works.” Anonymous types generate Equals(), GetHashCode(), and ToString() automatically, so you can group, compare, and debug them without extra code.
Great for internal, local use. When passing data between local methods or grouping temporary values, anonymous types communicate that this object exists only within a narrow scope—no need to pollute your public API with a class.
Cautions
Never expose them in public APIs. Anonymous types are compiler-generated and invisible to callers. If your method returns an anonymous type, users can’t see or reference the actual type. Use named types for public contracts.
Property names matter for equality. Two anonymous types with the same properties in the same order are considered the same type by the compiler—but order and naming are significant. Changing property order creates a new type.
They’re immutable (sort of). Anonymous types have read-only properties by default, but the object reference itself is mutable. You can’t reassign properties, which is good for safety but different from C# 9 records where you get with expressions for immutable updates.
Debugging and inspection can be tricky. Since the type is generated, debuggers show it as <>f__AnonymousType0<int, string> rather than a readable name. In complex code, this hampers readability. Consider naming your types if the shape is important to understand.
Not suitable for reuse across methods. If you find yourself creating the same anonymous type shape in multiple places, that’s a signal to extract a named type. Reuse patterns belong in named classes, not anonymous types.
Shaping data with anonymous types in LINQ
Anonymous types let you pluck just the fields you need from a query without defining a new class.
Valid since C# 3.0
var result = new[]
{
new { Name = "Alice", Age = 30 },
new { Name = "Bob", Age = 25 }
};
var linqProjection = result.Select(p => new { p.Name, UpperName = p.Name.ToUpper() });
Creating temporary objects inline
Use anonymous types to group related values for local use without ceremony.
Valid since C# 3.0
var person = new { FirstName = "John", LastName = "Doe", Age = 28 };
var location = new { City = "Seattle", State = "WA", ZipCode = "98101" };
Console.WriteLine($"{person.FirstName} {person.LastName} lives in {location.City}, {location.State}");