유니티에서 사용하는 어트리뷰트 [Serializable] 에 대해서 정리해본다.
[Serializable] 은 C#의 직렬화 시스템에 포함된 특성으로,
객체 데이터를 저장하거나 네트워크를 통해 전송할 수 있도록
이진 혹은 텍스트 형태(JSON)로 변환 가능하게 만들어주는 표식이다.
유니티에서는 자체 직렬화 시스템에 맞게 카스터마이즈해서 사용하기도 한다.
유니티를 개발하면서, 보통 Serializable는 직렬화 하기 위한 도구로 인식된다.
유니티에서 대게 직렬화는 인스펙터 창에 표시하기 위함인데,
이것은 Serializable을 커스터마이즈한 것이지, 본질적인 개념이 아니다.
Serializable는 데이터를 객체가 아니라 데이터로서 다루겠다는 선언이다.
C#에서 클래스는 논리와 행동을 가진 런타임 개체이다.
반면 유니티의 직렬화 시스템은 런타임 객체가 아니라 데이터의 구조에 관심을 둔다.
[Serializable]
public class Weapon
{
public string name;
public int damage;
}
이 코드는 단순히 직렬화 가능하게 선언한 것으로 이해할 수 있다.
직렬화는 객체를 데이터로 변환하는 것으로
이 클래스의 데이터가 기록할 수 있는 구조체로 쓸 수 있음을 기록한 것으로도 이해 할 수 있다.
정리하자면
[Serializable]은 클래스가 ‘행동하는 객체’가 아니라, ‘저장 가능한 상태 데이터’임을 시스템에 선언하는 의지의 표현이다.
유니티에서 [SerializeField]와 [Serializable]의 근본적인 차이는 무엇일까?
이것은 필드 레벨과 타입 레벨의 개념 차이를 이해하면 본질을 파악할 수 있다.
| 속성 | [SerializeField] | [Serializable] |
|---|---|---|
| 적용 대상 | 필드(field) | 타입(class/struct) |
| 역할 | 개별 필드를 유니티 직렬화 대상에 포함시킴 | 타입 자체를 유니티 직렬화 시스템에 등록시킴 |
| 목적 | 비공개 필드도 저장 및 인스펙터 표시 가능하게 함 | 해당 타입의 인스턴스를 인스펙터/저장 대상으로 만들기 위해 |
| 생략 가능? | public 필드는 자동 직렬화 (그러나 명시가 안전) | 반드시 명시해야 유니티 직렬화 시스템에 등록됨 |
| 런타임 영향 | 없음 | 없음 |
Serializable은 유니티 직렬화 시스템에 “이 타입을 등록하는 선언” 이고,
이는 마치 타입 수준의 선언이다.
"이 타입은 내 필드들을 저장하고 복원할 수 있는 구조다"라고 정의하는 것.
SerializeField는 유니티 직렬화 시스템에 “이 필드를 포함시키는 선언” 이다.
이는 개별 필드에 대한 접근 권한을 유니티에 부여하는 것.
“비공개지만 저장 대상이다”라고 알려주는 역할.
그렇다면 [Serializable]이 가능한 조건은 뭘까?
[Serializable], 직렬화는 다음 조건을 모두 만족해야한다.
public이거나 [SerializeField]가 붙어야 한다abstract, interface, delegate는 불가능Property, Event, Method는 무시됨아래는 유니티에서 직렬화가 불가능한 것들이다.
일부는 우회하거나 커스텀으로 해결 가능하다.
| 불가 타입 | 이유 |
|---|---|
Dictionary<K,V> | 비직렬화 구조 |
HashSet<T> | 유니티가 지원하지 않음 |
Queue, Stack | 지원 안 됨 |
interface 타입 | 구체 타입이 없기 때문 |
abstract class | 마찬가지로 인스턴스화 불가 |
Nullable<T> (int?, bool? 등) | 지원 안 함 |
Property, Event, Method | 상태가 아닌 동작이므로 |