[C#] 프로퍼티(Property)

2022. 2. 15. 22:22Languages/C#

*이 글은 <유니티 C# 스크립팅 마스터하기> 책을 바탕으로 공부한 글입니다. 문제 시, 삭제하겠습니다.

 

 

 

1. 프로퍼티(Property)

 

외부에서 어떤 클래스 내부의 변수를 사용할 때, 해당 변수를 이곳 저곳에서 가져가 사용하는 곳에서마다 조건을 보는 것은 비효율적일 수 있습니다. 일반적으로는 다음과 같이 원할 겁니다.

 

  • 변수의 값이 항상 올바르도록 강제하여, 할당된 값을 확실히 하길 바랄 경우
    • 예를 들어, 플레이어 체력을 0 ~ 100에만 값 할당하기, 정해진 조합만을 허용하는 문자열 변수 만들기 등
  • 변수의 값이 변경되었을 때를 감지하여, 이 값에 영향을 받는 다른 함수나 동작을 실행하길 원할 경우

 

이에 활용할 수 있는 것이 바로 프로퍼티(Property)입니다.

 

 


2. 프로퍼티의 사용 예시

 

1) 정해진 범위 내의 값만 할당하기

 

대략적인 사용 예시 형태는 다음과 같습니다.

public class Example : MonoBehaviour
{

    public float HP      // '_hp' 변수에 대한 프로퍼티
    {
        get
        {
            return _hp;
        }

        set
        {
            if(_hp >= 0f && _hp <= 100f)
            {
                _hp = value;
            }
        }
    }

    
    private float _hp;  // 실제 내부 클래스 변수

}
  • 변수처럼 선언되지만, 함수처럼 중괄호로 묶이는 것이 특징
  • get : 외부에서 해당 프로퍼티에 접근하여 읽어야 하는 상황에서 호출
  • set : 외부에서 해당 프로퍼티에 접근하여 값을 할당하는 상황에서 호출

 

위와 같이 프로퍼티의 set 함수에 조건부로 값을 할당받는 코드를 작성하면, 외부에서 해당 프로퍼티를 통해 변수에 값을 할당할 때 별도의 조건문이 필요없게 됩니다.

Example example = new Example();
example.HP = 10f;         // 올바른 값 할당
// example.HP = 5000f;    값이 할당되긴 하나, 프로퍼티 내부에서 필터링된다.

 

 

2) 특정 이벤트 발생시키기

 

변수의 값 변경 이벤트를 발생시키길 원한다면 프로퍼티를 통해서도 구현이 가능합니다.

    public float HP
    {
        get
        {
            return _hp;
        }

        set
        {
            if(_hp >= 0f && _hp <= 100f)
            {
                float preHp = _hp;
                _hp = value;

                if (!Mathf.Approximately(_hp, preHp))
                    OnChangeValue();
            }

        }
    }

 

 


3. 프로퍼티의 종류

 

읽기 전용 프로퍼티

public class Example : MonoBehaviour
{
    private float _hp;
    public float HP       // 읽기 전용
    {
        get
        {
            return _hp;
        }
    }

}

 

읽기 전용이므로 값 할당 불가능

 

 

쓰기 전용 프로퍼티

public class Example : MonoBehaviour
{
    private float _hp;
    public float HP          // 쓰기 전용
    {
        set
        {
            _hp = value;
        }
    }

}

 

쓰기 전용이므로 읽기 불가능

 

 

자동 구현 프로퍼티

 

  • 조건이 있는 것이 아닌, 단순히 변수 값 할당과 반환만 할 것이라면 자동 구현 프로퍼티 사용이 편함.
  • get, set 접근자 안에 아무것도 쓰지 않으면 됨.
  • 클래스 내부 변수에 대한 할당, 반환이 아닌 프로퍼티 그 자체를 사용하는 것.
public class Example : MonoBehaviour
{
   public float HP { get; set; }  // 자동 구현 프로퍼티
}
class ExternalClass
{
    public void Function()
    {
        Example example = new Example();
        example.HP = 50f;        // 프로퍼티 그 자체를 변수로 사용한다.
    }
}

 

 

프로퍼티 사용 팁

// 1. 프로퍼티는 선언과 동시에 필드에 대한 초기화 가능
public float HP { get; set; } = 100f;


// 2. 클래스 객체를 생성할 때도 초기화 가능
Example example = new Example() { HP = 100f };


// 3. 무명 형식 지원
var example = new { HP = 100f };   // 단, 한번 값 할당하면 변경 불가

 

 

초기화 전용 자동 구현 프로퍼티

 

C# 9.0에 도입된 기능으로, 기존에는 프로퍼티를 읽기 전용으로 선언하는 방법이 불편하였습니다.

생성자를 통해 필드를 초기화하고, 그 필드에 접근하는 프로퍼티는 get 접근자만 갖도록 해야 했죠.

// 기존 방식

class Monster
{
    private string name;
    private int hp;
    private int damage;
    
    public Monster(string name, int hp, int damage)
    {
        this.name = name;
        this.hp = hp;
        this.damage = damage;
    }
    
    public string Name { get {return name;} }
    public int HP { get {return hp;} }
    public int Damage { get {return damage;} }
}

 

 

이런 불편함은 자동 구현 프로퍼티에 init 접근자를 사용하면서 해결할 수 있습니다. set 접근자처럼 외부에서 프로퍼티를 변경할 수 있지만, 객체 초기화를 할 때만 가능하다는 점이 set 접근자와의 차이점입니다.

// 초기화 전용 자동 구현 프로퍼티

class Monster
{
    public string Name { get; init; }
    public int HP { get; init; }
    public int Damage { get; init; }
}

 

객체 생성 후, 해당 프로퍼티 내용을 수정하려고 하면 컴파일 오류가 발생하게 됩니다.

Monster monster = new Monster
        {
            Name = "Slime",
            HP = 500,
            Damage = 10
        };
        
        
// monster.HP = 1000;   컴파일 오류. 초기화 후 수정 불가

// 오류 메시지
"초깃값 전용 속성 또는 인덱서 "Monster.HP"은(는)
개체 이니셜라이저 또는 인스턴스 생성자나
'init' 접근자의 'this' 또는 'base'에만 할당할 수 있습니다."

 

 

 


4. 인터페이스와 추상 클래스의 프로퍼티

 

인터페이스 프로퍼티

 

인터페이스이므로 구현부는 갖지 않고, 인터페이스를 상속받는 클래스에서 반드시 해당 프로퍼티를 구현해야 합니다.

interface IMonster
{
    string Name     // 자동 구현 프로퍼티와 똑같이 생겼지만 컴파일러가 자동으로 구현해주지 않음 
    {
        get;
        set;
    }
}


class Monster : IMonster
{
    private string name;
    public string Name      // 자식 클래스는 기반 인터페이스에 선언된 모든 프로퍼티를 구현해야 함
    {
        get {return name;}
        set {name = value;}
    }
}

 

 

추상 클래스의 추상 프로퍼티

 

추상 클래스는 클래스처럼 구현된 프로퍼티를 가질 수도 있지만, 인터페이스처럼 구현되지 않은 프로퍼티도 가질 수 있습니다. 이것을 추상 프로퍼티(Abstract Property)라고 합니다.

abstract class AbstractMonster
{
    public int HP { get; set;}   // 자동 구현 프로퍼티
    abstract string Name         // 추상 프로퍼티
    {
        get;
        set;
    }
}


class Monster : AbstractMonster
{
    public override string Name   // 추상 프로퍼티 재정의 강제
    {
        get;
        set;
    }
}

 

 

 

728x90
반응형