Unity 개발 일지/코딩 공부

프로퍼티와 getter/setter 메서드

ohty20012 2025. 4. 11. 22:32

필드의 데이터 무결성을 유지하는 것은 매우 중요하다.

무결성의 중요성 자체는 여기서 다루지 않겠지만, 이를 지키기 위한 대표적인 방법이 바로 캡슐화이다. 그리고, C#에서 이를 구현하기 위해 프로퍼티를 주로 사용한다.

 

프로퍼티에는 크게 3가지 장점이 있다.

  1. 값 검증 및 제한
    • 프로퍼티의 set 블록에 조건 로직을 삽입함으로써, 외부에서 잘못된 값을 주더라도 내부에서 자동으로 교정하거나 거부할 수 있다.
  2. 캡슐화와 기능 삽입
    • 내부 필드에 대한 접근을 통제하면서, 접근 시 부가 기능도 함께 실행할 수 있다.
  3. 읽기와 쓰기 제어로 인한 무결성 유지
    • get, set 각각에 접근제어자를 독립적으로 지정할 수 있어서, 읽기 전용, 쓰기 전용, 둘 다 가능, 등 다양한 제한을 둘 수 있다.

 


 

 

프로퍼티는 간결성, 유연성, 커스텀 로직의 필요성에 따라 자동 구현 프로퍼티와 수동 구현 프로퍼티로 나눠진다.

 

1. 자동 구현 프로퍼티

public int Idx { get; set; }
  • idx라는 private 필드를 컴파일러가 자동으로 생성( = 백킹 필드).
  • 클래스 내부에서는 idx 값을 변경이 불가능하고, Idx의 값을 변경해야 한다.
  • 장점
    • 코드가 간결하다.
    • 캡슐화 된 접근제어 (private, init, 등)가 쉽다.
  • 단점
    • get이나 set 안에 로직을 넣을 수 없다 → 값 검증, 이벤트 발생, 캐싱 등이 필요해도 확장이 불가능
    • 백킹필드 조작 불가능

 

2. 수동 구현 프로퍼티

private int idx = 0;
public int Idx
{
    get { return idx; }
    set { idx = value; }
}
  • idx라는 필드를 수동으로 선언하고, 프로퍼티 Idx는 해당 필드를 반환만 한다.
  • idx와 Idx에 대한 제어를 완전히 프로그래머가 갖게 된다.
  • 장점
    • set이나 get 안에서 원하는 작업을 얼마든지 할 수 있다.
    • 백킹필드를 공유하거나 다르게 조작할 수 있다.

 

 


 

<  백킹필드 오류 >

 

프로퍼티를 다루다가

int idx = 0;
public int Idx { get; set; }

 

 

이 코드에서 오류는 발생하지 않았지만, 원하는 대로 idx 설정이 안되는 버그가 발생했다.

외부에서 idx 값을 set 했지만 제대로 반영이 안된 것이다.

그 이유가 뭘까?

 

[원인]

자동 구현 프로퍼티는 컴파일러가 Idx 전용의 백킹필드를 자동으로 생성한다.

그 과정에서 컴파일러가 백킹필드를 기존에 존재하던 idx 필드와 혼동하거나 이름이 중복될 수 있다.

따라서 필드 간 충돌이나 불명확한 의미로 인한 오류가 발생할 수 있다.

 

[예방]

자동 구현 프로퍼티를 사용할 때는 필드를 따로 만들지 말자.

필요한 경우에는 수동 구현 프로퍼티를 사용!

 

 

< 프로퍼티의 인스펙터 창 노출 >

 

위 시도를 한 이유는 idx 값을 인스펙터 창에 노출하기 위해서였다.

idx 필드를 선언하지 않으면 [SerializeField]도 붙일 수 없기 때문이다.

자동구현 프로퍼티를 인스펙터 창에 노출할 수는 없을까?

 

[대답]

Unity는 인스펙터에 표시할 수 있는 대상으로 직렬화 된 필드만 인식하기 떄문에, 기본적으로 프로퍼티는 인스펙터창에 표시할 수 없다.

 

[해결방법]

  1. 수동 구현 프로퍼티 사용
    • 수동 구현 프로퍼티는 필드를 선언하기 때문에 [SerializeField]를 붙일 수 있고, 추가적인 조작 또한 가능하다.
  2. OnInspectorGUI()
    • Unity의 OnInsepctorGUI() 재정의를 통해 수동으로 인스펙터에 프로퍼티를 띄울 수 있다.
    • 프로퍼티 외에도 다양하게 인스펙터를 커스터마이징 가능.
  3. [field : SerializeField] 사용
    • [field : SerializeField] public int Idx { get; set; }
    • Unity 2020.1 이상에서 사용 가능
    • 컴파일러가 생성하는 백킹필드에 [SerializeField]를 적용해주는 최신 C# 문법이다.

 

 

< private get; set; >

 

프로퍼티를 생성할때

// 읽기 전용
public int Idx { get; private set; }

// 읽기 쓰기 둘 다 가능
public int Idx { get; set; }

 

이 두 방식을 주로 사용한다.

 

public int Idx { private get; set; }

 

그렇다면 쓰기 전용은 사용하지 않는 것일까? 사용한다면 어떤 경우에 사용할까?

 

[대답]

가능하다. 일반적으로 사용하지는 않지만, 특수한 경우에 가끔 사용한다.

 

  1. 민감한 데이터 보호 : 비밀번호, 토큰, 시크릿 키 , 등 외부에서 설정은 허용하되 노출은 금지하는 필드
  2. 신호 전달 : 외부에서 신호만 전달하고, 내부에서 그 의미를 해석할 때
  3. 리셋이나 초기화 처리 : 특정 조건에서만 내부적으로 다뤄야 하는 값을 외부에 노출하지 않기 위해

[주의점]

  • 값 확인이 불가능하기 때문에 디버깅하기 어렵다.
  • 직렬화 대상이 아니기 때문에 Unity, JSON과의 호환성이 떨어질 수 있다.

 

 


 

< getter / setter 메서드 구현과의 비교 >

int idx = 0;

public int getIdx()
{
    return idx;
}
public void setIdx(int idx)
{
    this.idx = idx;
}

 

프로퍼티와 메서드 구현은 같은 기능을 하지만 문법적 간결함과 의도 전달 면에서 프로퍼티가 훨씬 깔끔하고 직관적이다.

하지만 메서드 구현이 필요할 때가 있다.

 

  1. 유니티 이벤트 시스템에서 직접 호출해야 할 때
    • 유니티 이벤트(Button 클릭, 등)에서는 프로퍼티 set에 직접 접근할 수 없기 때문에 메서드를 통해서만 가능하다.
      • 하지만 메서드를 통해서 set에 간접적으로 접근할 수 있다.
  2. 매개변수가 여러 개 있을 때
    • 프로퍼티는 get, set을 통한 단일 값 접근만 가능하지만, 메서드는 매개변수를 여러 개 받을 수 있다.
  3. 의도를 더욱 명확히 드러내고 싶을 때
    • ex) health 필드가 있을 때, Health 프로퍼티의 값을 -10 하는 것 보다
      Attacked() 메서드로 health -= 10 하는 게 의도가 명확하게 전달되고 직관적이다.
  4. 비동기 / 코루틴을 다루는 경우
    • 프로퍼티 내부에서는 yield return을 사용할 수 없기 때문에 코루틴 기반 로직은 반드시 매서드로 구현해야 한다.

 


 

 

 

프로퍼티는 무결성과 캡슐화를 자연스럽게 구현하는 객체지향의 핵심 도구이고,

단순한 필드 접근 수단이 아닌, 구조적 안정성과 설계 명확성의 시작점이다.

 

특히 Unity 같은 프레임워크 환경에서는 필드의 인스펙터 노출 여부, read only / write only , getter / setter 메서드 방식과의 차이를 이해하는 것이 실무의 완성도를 결정짓는 요소가 될 수 있다.

 

객체 설계에서 데이터 보호와 외부 인터페이스의 밸런스를 어떻게 설계할 것인가에 대해 고민하는 시간이었다.