블로그로 돌아가기
C#

C# record 사용법: 실무에서 바로 쓰는 핵심 가이드

c# record 사용법을 통해 불변(immutable) 데이터 모델을 정의하고 값 비교, 복사(with) 같은 실무 패턴을 안전하게 적용하는 방법과 주의점을 정리합니다. 실무 적용 흐름과 자주 하는 실수까지 함께 확인할 수 있습니다.

c# recordimmutabilitydotnetvalue equalitywith-expression
C# record 사용법을 설명하는 코드 스니펫이 있는 기술 블로그 썸네일

c# record 사용법이 필요한 상황

c# record 사용법을 배우면 불변 데이터 모델을 간편하게 만들고 값 기반 비교, 안전한 복사(with) 패턴을 실무 코드에 바로 적용할 수 있습니다. 이 글에서는 record의 핵심 개념, 코드 예제, 언제 쓰고 피해야 할지, 성능·보안·운영 관련 주의점과 실무 체크리스트까지 제공합니다. 독자는 실무 웹 개발자로서 DTO, 이벤트, 상태 객체에 record를 도입할 때 바로 참고할 수 있습니다.

c# record 사용법 핵심 개념

  • record는 C# 9에서 도입된 참조 타입(reference type) 기반의 특별한 타입입니다. 기본적으로 값 기반(value-based) 동등성(equality)을 제공합니다. 즉 필드 값이 같으면 같은 객체로 판단합니다.
  • positional record: 간결한 생성자와 프로퍼티 선언을 한 줄로 작성할 수 있습니다.
  • with 표현식: 기존 인스턴스를 변경하지 않고 일부 필드만 다른 새 인스턴스를 만들 때 사용합니다.
  • primary constructor와 init 접근자를 함께 사용하여 불변(immutable) 성격을 강화합니다.

c# record 사용법 실무 예제

다음은 DTO나 상태 객체로 자주 쓰이는 record의 실무 예시입니다.

// csharp public record UserDto(Guid Id, string Name, string Email); // 사용 예 var user1 = new UserDto(Guid.NewGuid(), "Alice", "alice@example.com"); var user2 = user1 with { Name = "Alice Kim" }; Console.WriteLine(user1 == user2); // false (값 비교라서 전체 값이 동일해야 true) // 레거시 클래스와 비교 public class UserClass { public Guid Id { get; } public string Name { get; } public string Email { get; } public UserClass(Guid id, string name, string email) { Id = id; Name = name; Email = email; } } var uc1 = new UserClass(user1.Id, user1.Name, user1.Email); var uc2 = new UserClass(user1.Id, user1.Name, user1.Email); Console.WriteLine(uc1 == uc2); // false (참조 비교)

record vs class 판단 표

구분항목1항목2항목3
내용record는 값 기반 동등성 제공class는 기본 참조 동등성record는 with로 안전한 복사 지원

위 표는 record와 class의 주요 차이를 실무 관점에서 간단히 정리한 것입니다.

언제 쓰면 좋고 언제 피해야 할까

  • 언제 쓰면 좋은가:

    • DTO, 이벤트 메시지, 상태 객체처럼 값 기반 비교가 더 적합한 경우
    • 불변(immutable) 모델을 기본으로 설계할 때
    • 복사해서 일부만 변경하는 패턴이 잦은 경우(with 표현식)
  • 언제 피해야 하는가:

    • 객체의 동일성(identity)이 중요하고 참조 비교를 필요로 하는 경우
    • 빈번한 가변 상태 변경(mutable)이 필수적인 성격의 도메인 엔티티
    • 성능상 인스턴스 생성 오버헤드가 엄격하게 제한되는 열핵심 루프

실무 체크리스트

  • DTO/이벤트가 불변 성격인지 확인했다.
  • 값 기반 동등성(Equals/GetHashCode)이 올바른지 검토했다.
  • 직렬화(예: JSON 직렬화) 시 프로퍼티 이름/순서가 의도대로 동작하는지 확인했다.
  • with 표현식을 사용하는 코드 경로에서 불필요한 객체 생성을 최소화했는지 확인했다.
  • 레거시 코드와 상호운용 시 Equals와 GetHashCode 정책을 문서화했다.

성능·보안·운영 주의점

성능:

  • record는 참조 타입이므로 인스턴스 생성 비용이 존재합니다. 짧은 라이프사이클의 대량 객체를 빈번히 만들면 GC 부하가 늘 수 있으므로 주의하세요.
  • 값 기반 Equals 구현은 모든 필드를 비교할 수 있기 때문에 필드 수가 많거나 중첩된 컬렉션이 있는 경우 비용이 증가합니다.

보안:

  • record를 통해 중요한 정보(예: 비밀번호, 시크릿 토큰)를 담아 전파할 때는 직렬화/로그 노출을 주의하세요. 불필요한 필드를 직렬화 대상에서 제외하거나 DTO 설계를 분리하세요.

운영:

  • 변경 시 호환성: record에 필드를 추가하면 기존 직렬화된 데이터와 호환성 문제가 생길 수 있습니다. 버전 관리 전략을 세우세요.
  • 로깅/모니터링: 값 기반 동등성 때문에 로그에 객체 내용을 찍을 때 민감정보가 포함되지 않도록 필드 검토가 필요합니다.

c# record 사용법 - 고급 팁

  • 레코드 상속: record는 다른 record를 상속할 수 있지만, 설계가 복잡해지면 불변성 규칙과 동등성 규칙을 헷갈릴 수 있으므로 단순하게 유지하세요.
  • 레코드로 인터페이스 구현: interface를 구현해 테스트 더블(test double)이나 DI에서 활용할 수 있습니다.
  • 레코드와 레코드 struct: C# 10부터 record struct가 있어 값 타입 레코드도 작성할 수 있습니다. 성능 특성에 따라 선택하세요.

자주 묻는 질문

Q1: record는 항상 불변인가요? A1: 기본으로 제공되는 positional record는 init 접근자를 사용해 초기화 후 변경이 어려운 패턴을 권장합니다. 그러나 프로퍼티를 mutable하게 선언하면 가변으로 사용할 수 있어 설계에 따라 달라집니다.

Q2: record와 class 중 어떤 걸 기본으로 써야 할까요? A2: 값 기반 동등성과 불변성이 중요하면 record를, 동일성(identity)과 가변 상태가 중요하면 class를 선택하세요.

Q3: record를 직렬화할 때 주의할 점은? A3: 직렬화 라이브러리(예: System.Text.Json)별로 생성자 바인딩이나 init 지원 차이가 있습니다. 테스트로 직렬화/역직렬화를 검증하고 필요 시 [JsonConstructor] 등 어노테이션을 사용하세요.

Q4: with 표현식이 성능에 나쁜가요? A4: with는 새 인스턴스를 생성하므로 대량 사용 시 GC 오버헤드가 증가할 수 있습니다. 핵심 루프에서는 주의하고, 필요한 경우 record struct나 다른 패턴을 고려하세요.

정리

  • c# record 사용법은 값 기반 동등성, 불변성, with 표현식으로 간결한 DTO/상태모델 설계를 가능하게 한다.
  • 언제 쓰면 좋은지(불변 DTO, 이벤트)와 피해야 할 경우(가변 엔티티, 성능 민감 루프)를 구분해 적용하라.
  • 직렬화, Equals/GetHashCode, 인스턴스 생성 비용을 실무 체크리스트로 검증하라.
  • 운영 관점에서 호환성과 로그/민감정보 노출을 반드시 고려하라.
c# record 사용법: 실무 적용 가이드와 주의점 | RYUSLOG DEV