[C#] record : 값 기반 비교와 불변 데이터 타입

[C#] record : 값 기반 비교와 불변 데이터 타입

안녕하세요. 이번 글에서는 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에 대해 간단히 알아보았습니다.

참고