Back to Blog
C#

C# Nested Object Initializer Syntax and Behavior

c# nested object initializer: Learn how to initialize nested objects and collections in C# using object and collection initializers, including runtime behavior and com...

C#Object InitializerNested ObjectsCollection Initializer.NETCode Readability
Diagram showing nested object initializer syntax in C# with braces and property assignments.

c# nested object initializer requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.

In C#, a nested object initializer lets you set properties of an object that is itself a property of another object, all within a single expression. This is a common pattern when constructing complex object graphs, such as DTOs, configuration models, or test fixtures. The syntax is concise and keeps related assignments together, but it also has specific runtime behavior and limitations that matter when you rely on it in production code.

What a Nested Object Initializer Looks Like

The core syntax extends the standard object initializer by placing another object initializer after a property assignment. Suppose you have two classes:

public class Address { public string Street { get; set; } public string City { get; set; } } public class Customer { public string Name { get; set; } public Address HomeAddress { get; set; } }

You can initialize a Customer and its HomeAddress in one statement:

var customer = new Customer { Name = "Alice", HomeAddress = new Address { Street = "123 Main St", City = "Springfield" } };

The inner new Address { ... } is a standard object initializer. The outer initializer assigns that new object to the HomeAddress property. This works because object initializers are evaluated as constructor calls followed by property assignments, and the inner expression is evaluated before the outer assignment.

How Nested Initializers Behave at Runtime

Object initializers are syntactic sugar. The compiler translates the previous example into code roughly equivalent to:

var customer = new Customer(); customer.Name = "Alice"; customer.HomeAddress = new Address(); customer.HomeAddress.Street = "123 Main St"; customer.HomeAddress.City = "Springfield";

This means the constructor of the outer object runs first, then each property setter is invoked in the order written. For the nested property, the inner object is constructed and its properties are set before the outer setter receives it. The outer object's constructor cannot rely on the nested object being present because the assignment happens after construction. If the outer constructor throws, the inner object is never created.

Another consequence is that the property setter for the nested property must be accessible. If HomeAddress is read-only or has a private setter, the initializer will not compile. The same rule applies to the inner object's properties.

Initializing Collections Inside Objects

Nested object initializers combine naturally with collection initializers. For example, a class that holds a list of addresses:

public class Customer { public string Name { get; set; } public List<Address> Addresses { get; } = new List<Address>(); }

You can populate the list directly in the initializer:

var customer = new Customer { Name = "Bob", Addresses = { new Address { Street = "1 Oak Ave", City = "Portland" }, new Address { Street = "2 Pine Rd", City = "Eugene" } } };

Here the Addresses property is read-only, but the collection initializer works because it calls Add on the existing list. The compiler translates this to:

var customer = new Customer(); customer.Name = "Bob"; customer.Addresses.Add(new Address { Street = "1 Oak Ave", City = "Portland" }); customer.Addresses.Add(new Address { Street = "2 Pine Rd", City = "Eugene" });

This pattern is useful when the collection is initialized in the constructor or as a property initializer, ensuring it is never null.

Mixing Object and Collection Initializers

You can nest collection initializers inside object initializers and vice versa. Consider a class representing an order with line items:

public class Order { public int Id { get; set; } public List<OrderLine> Lines { get; } = new List<OrderLine>(); } public class OrderLine { public string Product { get; set; } public int Quantity { get; set; } }

A single expression can create the order, its lines, and each line's properties:

var order = new Order { Id = 42, Lines = { new OrderLine { Product = "Laptop", Quantity = 1 }, new OrderLine { Product = "Mouse", Quantity = 2 } } };

This is convenient for test data or small fixed configurations. The readability is high because the entire object graph is visible at once. However, if the collection is large or built dynamically, a separate method or loop may be clearer.

Common Mistakes and Their Fixes

A frequent error is trying to initialize a property that is null. If HomeAddress is not initialized in the constructor and has no default value, the following fails at runtime:

var customer = new Customer { Name = "Carol", HomeAddress = { Street = "5 Elm St" } // CS1918 or runtime NullReferenceException };

The compiler error CS1918 occurs because the property is null; you cannot use a nested object initializer without creating a new object. The fix is to explicitly create the object:

HomeAddress = new Address { Street = "5 Elm St" }

Another mistake is using a nested initializer on a property with a private setter. The setter must be accessible from the calling code. If you need to initialize a read-only property, you must set it in the constructor or use a factory method.

Also, be careful with reference cycles. If two objects reference each other, a nested initializer cannot create the cycle because one object must exist before the other. You would need to assign the second reference after both objects are constructed.

Readability and Maintainability Tradeoffs

Nested object initializers reduce boilerplate and keep related data together. For small, fixed object graphs, they improve readability. But for deep hierarchies, the indentation can become unwieldy, and the order of assignments matters only for side effects, not for correctness. When the graph is built from dynamic input, a nested initializer is not suitable because you need conditional logic or loops.

A practical guideline is to use nested initializers when the structure is known at compile time and the number of nested elements is small. For larger or more variable structures, prefer building the object step by step or using a dedicated builder method. This keeps the code easier to debug because you can inspect intermediate states.

Performance and Allocation Considerations

Nested object initializers do not add runtime overhead compared to writing the assignments manually. The compiler emits the same IL. The only cost is the allocation of each object, which is inherent to the design. However, deeply nested initializers can create large object graphs in a single expression, making it harder to profile memory usage if you are not careful. For example, if a collection initializer adds thousands of items, the Add method is called repeatedly, which may be less efficient than using a constructor that accepts a range. But for typical use cases, the performance difference is negligible.

One subtle point is that the order of property assignments is guaranteed to be the order written. If a property setter has side effects, such as logging or validation, the nested initializer will trigger those side effects in that order. This can be useful for deterministic initialization, but it also means you should avoid putting expensive or inconsistent logic in setters when using initializers.

When to Use a Factory Method Instead

If a nested object graph requires validation, default values, or conditional creation, a factory method often produces clearer code. For example:

public static Customer CreateWithAddress(string name, Address address) { return new Customer { Name = name, HomeAddress = address }; }

This separates the construction logic from the caller and allows you to add checks before the object is returned. A nested initializer is a declarative construct; it cannot contain if statements or loops. When you need logic, move to a method or a builder. The choice depends on whether the object graph is static or dynamic. For static graphs, initializers are concise; for dynamic graphs, imperative code is more maintainable.

c# nested object initializer: Practical Usage and Code Examp | RYUSLOG DEV