C# 기초부터 마스터까지 — 3화
class, struct, record와 null 안전성 이해하기
본 블로그 작성 글들은, 강의를 목표로 하고 제작되었습니다. 또한 작성된 글의 정보도 틀렸을 수 있으니, 주의해주세요.
C#에서는 데이터를 class, struct, record로 표현할 수 있다. 문법이 비슷해도 복사 방식과 동일성의 의미가 다르므로 목적에 맞게 선택해야 한다.
class는 참조 형식이다
public sealed class Player
{
public string Name { get; }
public int Health { get; private set; }
public Player(string name, int health)
{
Name = name;
Health = health;
}
}
Player first = new("Rose", 100);
Player second = first;
second에는 객체 전체가 아니라 같은 객체를 가리키는 참조가 복사된다. 한쪽에서 Health를 바꾸면 다른 쪽에서도 바뀐 결과가 보인다.
struct는 값 형식이다
public readonly struct Position
{
public float X { get; }
public float Y { get; }
public Position(float x, float y)
{
X = x;
Y = y;
}
}
struct를 대입하면 값이 복사된다. 좌표나 색상처럼 작고 하나의 값으로 취급되는 데이터에 어울린다.
큰 struct는 복사 비용이 커지고 변경 가능한 struct는 예상하기 어려운 동작을 만들 수 있다. struct라고 무조건 빠른 것은 아니다.
record는 값 자체를 비교한다
public sealed record ItemKey(int Id, string Grade);
var a = new ItemKey(10, "Rare");
var b = new ItemKey(10, "Rare");
Console.WriteLine(a == b); // True
일반 class는 기본적으로 참조가 같은지 비교하지만 record는 구성 값이 같은지 비교한다. 설정, 명령, 네트워크 메시지처럼 불변 데이터에 사용하기 좋다.
null 가능성을 타입에 표시한다
Player? FindPlayer(int id)
{
return players.TryGetValue(id, out Player? player)
? player
: null;
}
Player? target = FindPlayer(10);
if (target is not null)
{
Console.WriteLine(target.Name);
}
nullable reference type을 사용하면 null이 가능한 참조와 아닌 참조를 구분할 수 있다. 경고를 !로 지우기 전에 정말 null이 불가능한지 흐름을 다시 확인해야 한다.
class, struct, record의 선택은 취향이 아니다. 객체의 정체성이 중요한지, 값의 복사가 자연스러운지, 불변 데이터인지부터 결정해야 한다.