C# Collection Initializers: Simplify Object Creation
Collection initializers in C# provide a concise, readable syntax for instantiating collections and populating them with elements in a single step. Introduced in C# 3.0, this language feature eliminates the need for repetitive, boilerplate code that previously required creating an empty collection and manually calling insertion methods. By streamlining how lists, dictionaries, and custom collections are populated, collection initializers make codebases cleaner, easier to maintain, and more declarative.
The Problem with Traditional Initialization
Before collection initializers, instantiating and populating a
collection required separate statements. Developers first had to
instantiate the collection object and then repeatedly call its
.Add() method.
// Traditional approach
List<string> fruits = new List<string>();
fruits.Add("Apple");
fruits.Add("Banana");
fruits.Add("Cherry");While functional, this approach is verbose and clutters the code, especially when dealing with nested collections or setting up test data.
The Collection Initializer Syntax
Collection initializers streamline this workflow by allowing you to
specify elements within enclosing braces {} directly after
the constructor call.
// Collection initializer approach
List<string> fruits = new List<string> { "Apple", "Banana", "Cherry" };Under the hood, the C# compiler transforms this syntax into standard
.Add() calls during compilation. The runtime performance
remains identical to the traditional approach, but the source code
becomes significantly more compact.
How Collection Initializers Work Under the Hood
For a class to support standard collection initializers, it must satisfy two requirements:
- It must implement the
System.Collections.IEnumerableinterface. - It must provide an accessible, non-static
Addmethod (or, since C# 6, an accessible extension method namedAdd).
Because of this mechanism, collection initializers also work seamlessly with complex objects:
public class User
{
public string Name { get; set; }
public int Age { get; set; }
}
List<User> users = new List<User>
{
new User { Name = "Alice", Age = 30 },
new User { Name = "Bob", Age = 25 }
};Initializing Dictionaries and Key-Value Collections
Collection initializers handle key-value pairs cleanly. C# offers two primary styles for dictionaries:
Nested Braces Syntax
var scores = new Dictionary<string, int>
{
{ "Alice", 95 },
{ "Bob", 80 }
};Index Initializer Syntax (C# 6+)
C# 6 introduced index initializers, which allow assigning values directly to keys using indexer notation:
var scores = new Dictionary<string, int>
{
["Alice"] = 95,
["Bob"] = 80
};The index syntax uses the dictionary's indexer
(scores["Alice"] = 95), which overwrites existing keys
rather than throwing an exception if a duplicate key is introduced
during initialization.
Key Benefits
- Improved Readability: Data definitions are declarative and clear, showing the collection's structure and contents immediately.
- Inline Usability: Collections can be created and passed directly into method calls without needing temporary local variables.
- Consistency: Combines seamlessly with object initializers to create deep, nested object graphs in a single, coherent statement.