안녕하세요. 이번 글에서는 C# 9.0에서 추가된 record에 대해 알아보겠습니다.
데이터를 담기만 하는 클래스를 만들 때도 생성자, 속성, Equals, GetHashCode, ToString을 직접 작성하면 코드가 길어집니다. record는 이런 “값 중심” 타입을 짧게 선언하고, 값 기반 비교와 불변성을 쉽게 얻을 수 있도록 만든 문법입니다.
기본 선언 : 위치 매개변수
가장 간단한 형태는 위치 매개변수(positional parameter)를 쓰는 선언입니다. 컴파일러가 생성자, init 전용 속성, Deconstruct, ToString 등을 자동으로 만들어 줍니다.
public record Person(string Name, int Age);
var p = new Person("Alice", 30);
Console.WriteLine(p); // Person { Name = Alice, Age = 30 }
var (name, age) = p; // 분해(Deconstruct)
Console.WriteLine($"{name}, {age}");
값 기반 동등성
class는 참조가 같아야 같은 객체로 보지만, record는 모든 속성 값이 같으면 같은 것으로 비교합니다.
public class PersonClass { public string Name { get; set; } = ""; }
public record PersonRecord(string Name);
var c1 = new PersonClass { Name = "Alice" };
var c2 = new PersonClass { Name = "Alice" };
Console.WriteLine(c1 == c2); // False (참조 비교)
var r1 = new PersonRecord("Alice");
var r2 = new PersonRecord("Alice");
Console.WriteLine(r1 == r2); // True (값 비교)
Console.WriteLine(ReferenceEquals(r1, r2)); // False
with 식으로 복사하며 변경
record의 속성은 기본적으로 init 전용이라 생성 후에 바꿀 수 없습니다. 값을 바꾼 새 객체가 필요할 때는 with 식으로 복사하면서 일부만 수정합니다.
var a = new Person("Alice", 30);
var b = a with { Age = 31 };
Console.WriteLine(a); // Person { Name = Alice, Age = 30 }
Console.WriteLine(b); // Person { Name = Alice, Age = 31 }
// a.Age = 40; // 컴파일 오류 : init 전용 속성
with는 얕은 복사(shallow copy)이므로 속성이 참조 타입이면 같은 객체를 가리킵니다.
record class, record struct
| 선언 | 종류 | 특징 |
|---|---|---|
| record / record class | 참조 타입 | C# 9.0, 기본 불변, 값 기반 동등성 |
| record struct | 값 타입 | C# 10, 위치 매개변수 속성은 기본 변경 가능 |
| readonly record struct | 값 타입 | C# 10, 불변 |
public readonly record struct Point(int X, int Y);
var pt = new Point(1, 2);
Console.WriteLine(pt); // Point { X = 1, Y = 2 }
주의할 점
- ToString, Equals, GetHashCode는 자동 생성되지만 직접 재정의할 수도 있습니다.
- 자동 생성되는 동등성은 속성 전체를 비교하므로 컬렉션 속성은 참조로 비교됩니다. 내용까지 비교하려면 별도 구현이 필요합니다.
- record도 상속할 수 있으며, 동등성 비교에는 런타임 타입이 함께 쓰입니다.
- Entity Framework처럼 변경 추적이 필요한 엔티티에는 맞지 않을 수 있어 DTO, 설정 값, 메시지처럼 불변 데이터에 주로 사용합니다.
정리
record는 데이터 중심 타입을 한 줄로 선언하고, 값 기반 비교와 불변성, with 식을 한꺼번에 제공합니다. 동일성이 중요한 객체는 class, 값 자체가 중요한 데이터는 record로 구분하면 의도가 코드에 잘 드러납니다.
이상으로 record에 대해 간단히 알아보았습니다.