7. Record 사용
위 예제에서 Car Class의 displacement Property는 객체가 생성되고 난 후 초기값이 결정되고 나서도 언제든 값이 바뀔 수 있습니다.
Car sedan = new();
sedan.displacement = 999;
Console.WriteLine($"{ sedan.displacement }");
sedan.displacement = 3000;
Console.WriteLine($"{ sedan.displacement }");
//999
//3000
하지만 객체의 인스턴스가 생성되는 순간에만 값이 결정되고 그다음 값이 바뀌지 말아야 하는 경우라면 Property의 set을 init으로 사용할 수 있습니다.
public class Car
{
public int displacement
{
get;
init;
}
}
이렇게 하면 해당 Property는 인스턴스 과정에서만 값이 초기화될 수 있고 그 이후로는 더 이상 값을 변경할 수 없게 됩니다.
Car sedan = new() { displacement = 999 };
위 예제에서와 같은 Property의 정의 방식은 필요한 부분에서 일부 불변성을 제공할 수 있습니다. 여기에서 좀 더 나아가 Type자체를 Class가 아닌 record를 통해 구현하여 인스턴스화 된 해당 객체 자체가 모두 init으로 설정된 불변성 형식임을 표현할 수 있습니다.
public record Car
{
public int Displacement
{
get;
init;
}
public string? Number
{
get;
init;
}
}
record는 기본적으로 인스턴스화 이후에 값이 바뀔 수 있는 field나 property를 가질 수 없는 것이 원칙입니다.(다만 기존 record를 통해 새로운 값을 가지게 되는 record를 생성하는 것은 가능한데 C#에서는 이러한 경우를 '비파괴적 변형(non-destructive mutation)'이라고 합니다.)
Car sedan = new() { Displacement = 999, Number = "1234" };
Console.WriteLine(sedan.Displacement);
● Positional data member
'Positional data member'는 record를 사용하는 측면에서 값의 할당과 확인 구문을 좀 더 간소화 시킬 수 있는 개념으로 사용될 수 있습니다.
public record Car
{
public int Displacement
{
get;
init;
}
public string? Number
{
get;
init;
}
public Car(int displacement, string? number)
{
Displacement = displacement;
Number = number;
}
public void Deconstruct(out int displacement, out string? number)
{
displacement = Displacement;
number = Number;
}
}
예제에서 Car record에는 생성자와 Deconstruct가 추가되었는데 이를 활용해 init이 적용된 Property에 값을 할당하거나 할당된 값을 가져오기 위한 구문이 이전보다 좀더 간소화되고 명료하게 바뀔 수 있습니다.
using mylibrary;
Car sedan = new(999, "1234");
var (dis, num) = sedan;
Console.WriteLine($"{dis}");
Console.WriteLine($"{num}");
//999
//1234