Quick Reference
record는 compiler-generated value equality와 with 복사를 제공합니다. record class는 같은 data라도 runtime type이 다르면 같지 않고, record struct는 값 타입 복사와 record equality를 함께 가집니다. with는 nested reference를 복제하지 않는 얕은 복사입니다.
public record User(string Name, int Level);
User first = new("Mina", 5);
User second = new("Mina", 5);
User senior = first with { Level = 6 };
Console.WriteLine(first == second); // True
Console.WriteLine(first == senior); // False- 값 기반 equality는 data model의 같은 값이 같은 의미일 때 사용합니다.
with는 원본을 바꾸지 않고 새 record instance 또는 새 record struct value를 만듭니다.List<T>, 배열, 일반 class member는 원본·복사본이 공유할 수 있습니다.- equality에 참여하는 가변 값을
Dictionary/HashSetkey로 사용 중에 바꾸면 collection lookup을 깨뜨릴 수 있습니다.
Equality가 비교하는 것
record class와 record struct는 compiler가 property-by-property equality, hash code, ==/!=를 생성합니다. plain class의 기본 참조 equality와 목적이 다르며, plain struct의 기본 ValueType.Equals와도 생성 방식이 다릅니다.
public record Person(string Name);
public record Employee(string Name, int Id) : Person(Name);
Person person = new("Mina");
Person employee = new Employee("Mina", 1);
Console.WriteLine(person == employee); // False: runtime record type이 다름
public readonly record struct Point(int X, int Y);
Console.WriteLine(new Point(1, 2) == new Point(1, 2)); // Truerecord inheritance가 필요한 경우, 두 타입의 "같음"이 같은 domain identity인지 먼저 결정합니다. type이 다른 두 record를 같은 것으로 취급해야 한다면 generated equality에 기대기보다 별도의 comparer나 명시적 domain comparison을 만듭니다.
with와 얕은 복사
public record BuildOptions(string Name, List<string> Tags);
var original = new BuildOptions("dev", new List<string> { "fast" });
var copy = original with { Name = "prod" };
copy.Tags.Add("shared");
Console.WriteLine(original.Tags.Count); // 2
var independent = original with
{
Name = "test",
Tags = new List<string>(original.Tags),
};with가 바꾸지 않은 member는 reference 자체를 복사합니다. immutable array·immutable collection·새 collection construction을 선택할지는 data ownership과 변경 정책에 따라 정합니다. with가 deep copy나 validation lifecycle을 자동으로 실행한다고 가정하지 않습니다.
Hash key와 가변 상태
public record MutableKey
{
public int Id { get; set; }
}
var key = new MutableKey { Id = 1 };
var set = new HashSet<MutableKey> { key };
key.Id = 2;
Console.WriteLine(set.Contains(key)); // equality/hash 정책에 따라 lookup 계약이 깨질 수 있음key를 collection에 넣은 뒤 equality/hash에 들어가는 member를 바꾸지 않습니다. record 자체가 mutable property를 선언할 수 있으므로, key·message·snapshot은 init/읽기 전용 member와 immutable nested data를 우선합니다.
record의 선언 형태와 record class/struct 선택은 record 기본에서 확인합니다.
자주 틀리는 부분
generated member의 내부 이름이나 compiler 구현을 public contract처럼 사용하지 마세요. with와 equality의 언어 수준 동작에 의존하고, 복사 전략·validation·domain identity는 타입 API에서 명시합니다.
record가 값 비교를 지원해도 모든 property graph가 깊게 비교되는 것은 아닙니다. 참조 멤버의 equality와 불변성은 그 멤버 type의 contract를 따릅니다.
참고 링크
2 sources