← SEARCHABLE ARCHIVE
C# · 2026-07-21

C# 기초부터 마스터까지 — 3화

class, struct, record와 null 안전성 이해하기

INTERACTIVE READING MODE →

본 블로그 작성 글들은, 강의를 목표로 하고 제작되었습니다. 또한 작성된 글의 정보도 틀렸을 수 있으니, 주의해주세요.

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의 선택은 취향이 아니다. 객체의 정체성이 중요한지, 값의 복사가 자연스러운지, 불변 데이터인지부터 결정해야 한다.