접근자/설정자 메서드를 둬서 필드 접근에 대한 단일 창구를 제공하는 것은 바람직하지만 매번 메서드를 작성한다면 번거로운 작업이 될 것이다.
이런 단점을 보완하기 C#에서는 프로퍼티(property)라는 문법을 제공한다.
프로퍼티는 속성으로 번역되지만, 객체지향에서 말하는 attribute와는 다른 뜻이다.
- 객체 지향에서 말하는 속성(attribute): C#에서의 필드(field)
- C#에서의 속성(property): 접근자/설정자 메서드에 대한 편리한 구문
프로퍼티를 사용하기 전에 Getter/Setter에 대해 간단히 이해하고 넘어가자.
class Knight
{
public int hp;
}
static void Main(string[] args)
{
// knight 객체 생성
Knight knight = new Knight();
// hnight의 hp접근
knight.hp = 100;
}
Knight의 hp는 public으로 선언되었기 때문에 누구든 접근할 수 있게 되고, 다수가 작업할 때 실수로 누군가 hp 값을 건드리게 된다면 원치 않던 버그나 에러가 일어날 것이다.
그렇기 때문에 Getter/Setter 메서드를 만들어 hp에 직접적으로 접근하지 말고 GetHp(), SetHp()등의 메서드를 만들어 접근하게 만드는 것이다.
이때 hp는 외부에서 변경할 수 없도록 private나 protected 등을 이용해 접근을 제한한다.
class Knight
{
// 외부에서 변경할 수 없도록 private나 protected를 사용한다.
protected int hp;
// Getter 혹은 Get함수
public int GetHp() { return hp; }
// Setter 혹은 Set함수
public void SetHp(int hp) { this.hp = hp; }
}
static void Main(string[] args)
{
Knight knight = new Knight();
// knight의 hp를 GetHp()로 불러온다.
int hp = knight.GetHp();
// knight의 hp를 SetHp()로 설정한다.
knight.SetHp(100);
}
이렇게 하면 hp를 변경한 부분을 찾고 싶다면 디버깅할 때 SetHp()에 잡혀 어디서 건드렸는지 알 수 있다.
그리고 특정 경우에만 hp를 변경하고 싶다면, SetHp(Setter) 메서드에 조건을 추가하면 된다.
예를 들어 무적 상태에는 hp를 변경할 수 없다면 아래 코드처럼 작성하면 된다.
// Setter 부분에 조건을 추가
public void SetHp(int hp)
{
// 무적 상태가 아니라면 hp를 설정한다.
if(!invincibility_state)
this.hp = hp;
}
C++에서는 이런 식으로 매번 Getter/Setter를 구성하는 게 제일 나은 방법일 수 있지만,
C#에서는 간편하게 사용할 수 있는 문법을 제공하는데 이것을 프로퍼티라고 한다.
class 클래스명
{
타입 필드명;
접근제한자 데이터타입 프로퍼티명
{
get { return 필드명; }
set { 필드명 = value; }
}
}
get으로는 값을 읽기 때문에 필드명을 반환하고,
set으로는 값을 설정하기 때문에 value라는 키워드를 이용하여 값을 설정한다.
위에서 사용했던 GetHp(), SetHp()의 기능을 똑같이 프로퍼티를 이용해서 구현해보자.
class Knight
{
protected int hp;
// Hp 프로퍼티
public int Hp
{
get { return hp; }
set { hp = value; }
}
}
static void Main(string[] args)
{
Knight knight = new Knight();
// GetHp와 Hp는 같은 역할을 한다.
// int hp = knight.GetHp();
int hp = knight.Hp;
// SetHp와 Hp는 같은 역할을 한다.
// knight.SetHp(100);
knight.Hp = 100;
}
내용이 길다면 get과 set을 한 줄에 사용하지 않아도 되며,
set 없이 get만 설정하여 읽기 전용 프로퍼티로 만들 수 있다.
외부에서 읽는 것은 가능하나 설정을 막고 싶다면 set 앞에 접근 제한자를 사용해주면 된다.
public int Hp
{
get { return hp; }
private set { hp = value; }
}
void TestSetHp() { Hp = 100; }
이렇게 접근 제한자로 private을 사용했다면 클래스 내부의 함수에서만 접근이 가능하다.
자동 구현 프로퍼티는 프로퍼티를 더 간단하게 사용할 수 있도록 만들어준다.
위에서 구현한 Knight 클래스의 Hp 프로퍼티를 자동 구현 프로퍼티로 만들어보자.
class Knight
{
// 자동 구현 프로퍼티
public int Hp { get; set; };
}
자동 구현 프로퍼티를 이용하면 기존의 코드와 비교했을 때 엄청나게 간단해진 것을 확인할 수 있다.
// Getter/Setter를 사용할 경우
int hp;
public int GetHp() { return hp; }
public void SetHp(int hp) { this.hp = hp; }
// 프로퍼티를 사용할 경우
int hp;
public int Hp{ get { return hp; } set { hp = value; } }
// 자동 구현 프로퍼티를 사용할 경우
public int Hp { get; set; };
자동 구현 프로퍼티는 사실 컴파일할 때 Getter/Setter를 사용한 것과 유사하게 작동한다.
컴파일러가 겹치지 않는 변수를 만들고 Getter와 Setter를 구분해 사용해준다고 생각하면 된다.
또한 접근 한정자를 사용할 수 있으며, 선언과 동시에 초기화도 가능하다.
인프런 [C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part1: C# 기초 프로그래밍 입문 강의를 듣고 공식 문서를 참고하여 정리한 글 입니다.
개인 공부를 정리한 글이기 때문에 틀린 부분이 있을 수 있습니다.