Quick Reference
[SerializeField] private는 외부 C# API를 열지 않은 채 Inspector·scene·prefab 데이터에 field 값을 저장하는 기본 방식입니다. Unity serialization은 property가 아니라 field를 직접 읽고 쓰므로, Inspector 변경은 property setter나 validation method를 자동 호출하지 않습니다.
| field 형태 | Inspector/asset 저장 | 이유와 대안 |
|---|---|---|
public 또는 [SerializeField] private non-static field | 지원 타입이면 저장 | 설정값·reference에 사용 |
static, const, readonly | 저장하지 않음 | runtime/shared state 또는 code constant로 분리 |
| property | 직접 저장하지 않음 | backing field를 serialize하고 property는 API로 제공 |
array, List<T> of serializable type | 저장 | 순서 있는 설정 목록에 사용 |
Dictionary, jagged/multidimensional/nested container | 기본 field serialization 대상 아님 | wrapper, callback, 별도 serializer 검토 |
[SerializeField] private float moveSpeed = 5f;
[SerializeField] private Transform target;
public float MoveSpeed => moveSpeed;Inspector에 저장되는 field
field가 Inspector에 저장되려면 public이거나 [SerializeField]여야 하고, static·const·readonly가 아니며 Unity가 지원하는 타입이어야 합니다. primitive, enum, UnityEngine.Object reference, [System.Serializable] custom struct/class, 이들의 array와 List<T>가 기본 범위입니다. custom class를 value 형태로 serialize하면 UnityEngine.Object reference처럼 독립 asset identity를 갖는 것이 아니라 해당 MonoBehaviour/ScriptableObject의 데이터 안에 포함됩니다.
using System;
using UnityEngine;
[Serializable]
public struct DamageRange
{
public int min;
public int max;
}
public sealed class WeaponConfig : MonoBehaviour
{
[SerializeField] private DamageRange damage;
[SerializeField] private List<AudioClip> hitClips = new();
}Inspector는 MoveSpeed property가 아니라 moveSpeed field를 직접 바꿉니다. 값 범위 보정이나 dependent cache 갱신이 필요하면 OnValidate로 Editor 변경을 다루거나, runtime 설정 API에서 별도 검증합니다. OnValidate가 build runtime 입력을 검증해 주는 것은 아닙니다.
이름 변경과 데이터 migration
serialized field 이름을 바꾸면 기존 prefab·scene의 값은 새 field에 자동으로 옮겨지지 않을 수 있습니다. rename에는 UnityEngine.Serialization.FormerlySerializedAs를 사용하고, 실제 prefab·scene을 열어 migration 결과를 확인합니다.
using UnityEngine;
using UnityEngine.Serialization;
public sealed class HealthView : MonoBehaviour
{
[FormerlySerializedAs("hitpoints")]
[SerializeField] private int maxHealth = 100;
}FormerlySerializedAs는 Editor data migration을 돕는 attribute이지 build에서 저장 파일 schema를 변환하는 일반 시스템이 아닙니다. Player save data는 별도의 version과 migration policy를 갖게 합니다. Inspector reference가 null이면 field는 정상적으로 serialize돼도 scene/prefab override에서 대상이 빠졌을 수 있으므로, 어느 asset의 어느 instance가 값을 소유하는지 확인합니다.
Runtime 상태와 Inspector 상태
Play Mode에서 field 값을 바꿔도 기본적으로 scene/prefab source asset에 영구 저장되는 runtime save 기능은 아닙니다. Editor에서 변경한 serialized data와 runtime session state, 플레이어 save file을 같은 것으로 취급하지 않습니다. script reload에서는 조건에 맞는 private field도 복원될 수 있어, reload 뒤 반드시 초기화돼야 하는 transient cache는 [NonSerialized] 또는 lifecycle 초기화를 고려합니다.
[SerializeReference]는 polymorphic managed reference처럼 일반 field serialization으로 표현하기 어려운 object graph에 쓰는 별도 도구입니다. 단순 config에 습관적으로 쓰면 Inspector·diff·migration 복잡도가 커질 수 있으므로, 실제로 다형 타입 identity가 필요한 경우에만 선택합니다.
자주 틀리는 부분
| 증상 | 원인 | 수정 |
|---|---|---|
| Inspector 값 변경에서 property setter가 안 불림 | Unity가 field를 직접 직렬화 | backing field와 OnValidate/명시적 runtime API를 분리 |
Dictionary가 Inspector에 저장되지 않음 | 기본 field serialization 지원 범위 밖 | wrapper·ISerializationCallbackReceiver·별도 data format 검토 |
| field rename 뒤 기존 값이 사라짐 | serialized name 변경만 수행 | FormerlySerializedAs 추가 후 asset migration 확인 |
| Play Mode에서 바꾼 값이 다음 실행에 없음 | runtime state를 asset 저장으로 오해 | persistent save 시스템 또는 Editor 작업으로 분리 |
| static cache가 reload 뒤 초기화됨 | static field는 Unity serialization 복원 대상 아님 | 초기화 지점과 domain reload 정책을 명시 |
참고 링크
3 sources