숏컷 코드
// 컬렉션 초기화식
var numbers = new List<int> { 1, 2, 3, 4 };
var scores = new Dictionary<string, int>
{
["Mina"] = 1200,
["Jin"] = 980,
};
// C# 9+ target-typed new
List<int> primes = new() { 2, 3, 5, 7 };
// C# 12+ 컬렉션 식
int[] arr = [1, 2, 3];
List<int> list = [1, 2, 3];문법
어떤 초기화 문법을 먼저 고르면 되나
| 상황 | 먼저 떠올릴 것 |
|---|---|
| 모든 버전에서 가장 무난 | new T { ... } |
| 왼쪽 타입이 분명함 | new() { ... } |
| C# 12 이상, 짧은 통일 문법 | [...] |
| 기존 컬렉션 합치기 | [..a, ..b] |
컴파일러가 초기화식을 변환하는 방법
컬렉션 초기화식은 문법 설탕(syntactic sugar) 입니다. 컴파일러가 Add() 호출로 변환합니다.
// 이 코드는 아래와 완전히 동일합니다
var numbers = new List<int> { 1, 2, 3 };
// 컴파일러가 생성하는 코드
var temp = new List<int>();
temp.Add(1);
temp.Add(2);
temp.Add(3);
var numbers = temp;딕셔너리의 ["key"] = value 형태는 Add(key, value) 대신 인덱서를 쓰는 것으로, 키가 이미 있으면 덮어씁니다.
target-typed new() (C# 9+)
타입을 왼쪽에서 추론할 수 있으면 오른쪽의 타입 이름을 생략할 수 있습니다. 제네릭 타입이 길 때 특히 유용합니다.
Dictionary<string, List<int>> map = new()
{
["a"] = new() { 1, 2, 3 },
["b"] = new() { 4, 5, 6 },
};컬렉션 식 (C# 12+)
[...] 문법은 배열, List<T>, ImmutableArray<T> 등 다양한 컬렉션 타입에 통일된 초기화 문법을 제공합니다. 스프레드 연산자(..) 로 기존 컬렉션을 펼쳐 넣을 수 있습니다.
int[] first = [1, 2, 3];
int[] second = [4, 5, 6];
int[] all = [..first, ..second, 7, 8]; // [1,2,3,4,5,6,7,8]
// ReadOnlySpan<T>에도 사용 가능 — 힙 할당 없음
ReadOnlySpan<int> span = [1, 2, 3];// ❌ target type이 없으면 컬렉션 식 타입을 추론할 수 없음
// var items = [1, 2, 3];
// ✅ 왼쪽에서 타입을 알려 줘야 함
int[] items = [1, 2, 3];
List<int> list = [1, 2, 3];체크포인트
| 문법 | C# 버전 | 특징 |
|---|---|---|
new T { ... } | 초기 | 가장 범용, 모든 버전 |
new() { ... } | 9+ | 타입 이름 생략 가능 |
[...] | 12+ | 통일된 문법, 스프레드 지원 |
..spread | 12+ | 기존 컬렉션을 인라인으로 펼침 |
주의할 점
초기화 블록에 값이 너무 많아지면 코드보다 데이터 파일(JSON, CSV 등)로 관리하는 편이 낫습니다. 코드에 수십 개의 초기값을 나열하면 가독성이 떨어지고 변경 이력 추적도 어려워집니다.
컬렉션 식 [...]은 컴파일러가 타입을 추론할 수 있어야 합니다. var items = [1, 2, 3];처럼 타입 정보가 없으면 컴파일 오류가 납니다.
참고 링크
2 sources