Skip to main content
An anonymous type is a compiler-generated, immutable reference type that encapsulates a set of read-only properties into a single object without requiring an explicit class declaration. The compiler infers the type based on the object initializer and assigns it an internal, unutterable name at compile time. Because the exact type name is inaccessible in source code, you must use the implicitly typed local variable keyword (var) to hold the reference if you want to maintain strong typing and access the properties directly at compile time. Assigning the instance to an object variable forfeits direct property resolution. Assigning it to a dynamic variable forfeits compile-time type safety, though it defers property resolution to runtime.

Compiler Behavior and Mechanics

When the C# compiler encounters an anonymous type declaration, it generates a sealed internal class deriving directly from System.Object. To optimize type generation, the compiler creates a generic class based on the property names and their order. The property types are passed as generic type arguments. For the example above, the compiler generates a structure conceptually similar to this valid C# representation:

Type Unification

The compiler optimizes anonymous types through type unification. If multiple anonymous type declarations within the same assembly specify the exact same property names and in the exact same order, the compiler maps them to the same underlying generic class definition. If the property types also match, they share the exact same constructed type.

Equality Semantics

Although anonymous types are reference types, the compiler overrides the Equals and GetHashCode methods to enforce value equality semantics. Two anonymous type instances are considered equal if and only if all their corresponding properties are equal.
The compiler also overrides the ToString method to output a concatenated string of the property names and their current values.

Projection Initializers

You can omit explicit property names during instantiation if you are initializing the anonymous type from existing variables or member accesses. The compiler projects the variable or member name as the property name.

Non-Destructive Mutation

Because anonymous types are strictly immutable, their properties cannot be reassigned after initialization. However, starting in C# 10, anonymous types support the with expression, which allows for non-destructive mutation. This creates a new instance of the anonymous type, copying the existing values and applying the specified modifications.
Tired of Poor C# Skills? Fix That With Deep Grasping!Learn More