`new` 연산자 — 타입의 새 인스턴스를 만들고 초기화해요

new 연산자 — 타입의 새 인스턴스를 만들고 초기화해요

C#에서 객체를 새로 만들 때는 new 연산자를 써요. new 연산자는 타입의 새 인스턴스를 생성하고, 경우에 따라 그 인스턴스를 한 번에 초기화하기도 해요. 참고로 new 키워드는 이 용도 외에도 멤버 선언 한정자제네릭 타입 제약으로도 쓰이는데, 이 문서에서는 연산자로서의 new만 다룰게요.

출처: new operator - Create and initialize a new instance of a type

본문

생성자 호출

타입의 새 인스턴스를 만들려면 new 연산자를 사용해서 그 타입의 생성자 중 하나를 호출하면 돼요.

var dict = new Dictionary<string, int>();
dict["first"] = 10;
dict["second"] = 20;
dict["third"] = 30;

Console.WriteLine(string.Join("; ", dict.Select(entry => $"{entry.Key}: {entry.Value}")));
// Output:
// first: 10; second: 20; third: 30

new 연산자와 함께 객체 또는 컬렉션 이니셜라이저를 쓰면, 객체를 만들고 초기화하는 작업을 한 문장으로 끝낼 수 있어요. 아래 예시를 볼게요.

var dict = new Dictionary<string, int>
{
    ["first"] = 10,
    ["second"] = 20,
    ["third"] = 30
};

Console.WriteLine(string.Join("; ", dict.Select(entry => $"{entry.Key}: {entry.Value}")));
// Output:
// first: 10; second: 20; third: 30

대상 형식의 new (Target-typed new)

생성자 호출 식은 대상 형식에 맞춰져요(target-typed). 즉, 식의 대상 타입이 이미 정해져 있다면 타입 이름을 생략해도 돼요. 아래 예시를 보면 감이 올 거예요.

List<int> xs = new();
List<int> ys = new(capacity: 10_000);
List<int> zs = new() { Capacity = 20_000 };

Dictionary<int, List<int>> lookup = new()
{
    [1] = new() { 1, 2, 3 },
    [2] = new() { 5, 8, 3 },
    [5] = new() { 1, 0, 4 }
};

위 예시처럼 대상 형식의 new 식에는 항상 괄호 ()를 붙여줘야 해요. 반대로 new 식의 대상 형식이 알려지지 않은 경우, 예를 들어 var 키워드를 쓴다면 타입 이름을 반드시 명시해야 해요.

배열 생성

new 연산자는 배열 인스턴스를 만들 때도 사용해요.

var numbers = new int[3];
numbers[0] = 10;
numbers[1] = 20;
numbers[2] = 30;
Console.WriteLine(string.Join(", ", numbers));
// Output:
// 10, 20, 30

배열 초기화 구문을 쓰면 배열을 만들면서 요소까지 한 문장에 채울 수 있어요. 그 방법이 여러 가지인데, 아래 예시에서 확인해 볼게요.

var a = new int[3] { 10, 20, 30 };
var b = new int[] { 10, 20, 30 };
var c = new[] { 10, 20, 30 };
Console.WriteLine(c.GetType());  // output: System.Int32[]

배열에 대해 더 자세한 내용은 배열 문서를 참고하세요.

익명 타입 인스턴스화

익명 타입의 인스턴스를 만들 때는 new 연산자와 객체 이니셜라이저 구문을 함께 사용해요.

var example = new { Greeting = "Hello", Name = "World" };
Console.WriteLine($"{example.Greeting}, {example.Name}!");
// Output:
// Hello, World!

타입 인스턴스의 소멸

이전에 만든 타입 인스턴스를 직접 파괴할 필요는 없어요. 시스템이 참조 타입과 값 타입의 인스턴스를 모두 자동으로 파괴하거든요. 값 타입의 인스턴스는 그 인스턴스를 담고 있던 컨텍스트가 파괴되는 즉시 파괴되고, 참조 타입의 인스턴스는 마지막 참조가 제거된 후 정해지지 않은 시점에 가비지 컬렉터가 파괴해요.

단, 파일 핸들처럼 관리되지 않는 리소스(unmanaged resource)를 담고 있는 타입 인스턴스는 조금 달라요. 그런 리소스를 최대한 빨리 해제하려면 결정적 정리(deterministic clean-up) 방식을 써야 해요. 자세한 내용은 xref:System.IDisposable?displayProperty=nameWithType API 참조와 using 문서를 확인해 주세요.

연산자 오버로드 가능 여부

사용자 정의 타입은 new 연산자를 오버로드할 수 없어요.

C# 언어 사양

더 자세한 내용은 C# 언어 사양The new operator 절을 참고하세요.

대상 형식의 new 식에 대해 더 알고 싶다면 C# 언어 사양Object creation expressions 절을 보면 돼요.

더 알아보기