var s1 = new StrangeRecord
{
A = 10,
B = "NAME1",
C = new object()
};
var s2 = s1 with { };
Console.WriteLine(s1 == s2); // True
Console.WriteLine(s1.C == s2.C); // True
Console.WriteLine(ReferenceEquals(s1.C, s2.C)); // True
record StrangeRecord
{
public int A { get; init; }
public string B { get; init; }
public object C { get; init; }
}
record의 with 용법은 record의 object 속성까지 어떻게 하지는 못합니다. 그런 메커니즘이 없기 때문인데요. record에 class로 만든 속성을 사용할 때 오용하지 않도록 주의해야 할 점인것 같습니다.
var m1 = new MustPredictableRecord
{
A = 10,
B = "NAME2",
C = new(10)
};
var m2 = m1 with { };
Console.WriteLine(ReferenceEquals(m1, m2)); // False
Console.WriteLine(m1 == m2); // True
Console.WriteLine(m1.C == m2.C); // True
Console.WriteLine(ReferenceEquals(m1.C, m2.C)); // True
record IntValue(int Value);
record MustPredictableRecord
{
public int A { get; init; }
public string B { get; init; }
public IntValue C { get; init; }
}
음 이건 좀 당황스럽습니다. InvValue는 record이고 깊은 복사를 기대했는데 말이죠. 그런데 생각해보면, 값이 같은 불변개체의 경우 굳이 새로운 인스턴스를 생성할 필요가 없기 때문에 문제 없는 동작이 됩니다.
IntValue
record를 값이 변할 수 있도록 다음과 같이 고쳐 보고 테스트를 진행해보았습니다.
record IntValue
{
public IntValue(int value) => Value = value;
public int Value { get; set; }
}
var m2 = m1 with { };
Console.WriteLine(ReferenceEquals(m1, m2)); // False
Console.WriteLine(m1 == m2); // True
Console.WriteLine(m1.C == m2.C); // True
Console.WriteLine(ReferenceEquals(m1.C, m2.C)); // True
m1.C.Value = 2;
Console.WriteLine($"{m1.C}, {m2.C}");
그러자 좀 불편한 결과를 확인할 수 있었습니다. record라 할지라도 불변하지 않으면 class와 동일한 오동작 코딩을 할 여지가 생깁니다.
결국에는 with
를 이용한 복사는 단지 변경 속성을 쉽게 쓸수 있게 할 뿐이지 속성이 참조형일 경우 class던 record던 얕은 복사를 한다는 점입니다.
record의 깊은 복사 방법에 대해서 아시는 분이 계실까요?