C# 공부를 하면서 처음으로 당황했던 부분
맨 처음에는 이게 변수인지 함수인지 정체를 몰라서 당황했었다
Property에 대한 얘기를 본격적으로 하기 전에,
OOP에서 자주 볼 수 있는 getter / setter 패턴에 대해 알아보자
getter / setter 란?
OOP를 공부하다 보면 캡슐화, 은닉화, 등등 추상적인 얘기를 많이 듣는데
도대체 언제 어떻게 쓰이는건지는 알려주지 않아 뜬구름잡는 얘기같다는 생각이 들때가 있다.
그중 getter / setter 패턴은
클래스의 필드에 접근하도록 도와주는 기능을 하는 패턴이다.
보통 OOP의 규칙에 따라 특별한 이유가 없는 한
클래스의 필드는 private로 지정한다.
OOP를 지향하는 C#에서는 접근 제한자를 설정하지 않으면 기본적으로 private로 설정해줄 만큼
필드를 private로 선언하는것은 꽤 중요하다.
그럼 왜 중요할까?
class Test
{
static void Main()
{
Student a = new Student();
a.score = 4200;
}
}
class Student()
{
public int score;
}
Student라는 클래스는 필드로 score를 가진다.
score가 4200점인데 100점 만점인 시험이니 잘못된 정보를 넣고있다는 것을 알 수 있다.
일단 필드가 public이기 때문에, 언제 어디서든 Student 객체만 만들면 그 코드 내에서 Student의 필드들을 맘대로 가져올수도, 고칠수도 있다.
하지만 이는 컴파일, 런타임 오류를 내지 않는, 프로그래머가 직접 논리를 따져서 고쳐야 하는 치명적인 버그이다.
이를 막기 위해 Student의 필드를 private로 바꾼 후,
OOP의 규율에 맞게 public getter / setter 함수들을 추가했다.
class Test
{
static void Main()
{
Student a = new Student();
a.SetScore(4200);
}
}
class Student()
{
private int score;
public int GetScore() {return score;}
public void SetScore(int score) {this.score = score;}
}
하지만 여전히 잘못된 정보가 그대로 들어가고 있다.
score의 setter 함수를 바꿔보자
class Test
{
static void Main()
{
Student a = new Student();
a.SetScore(4200);
}
}
class Student()
{
private int score;
public int GetScore() {return score;}
public void SetScore(int score)
{
if(score > 100)
this.score = 100;
else if(score < 0)
this.score = 0;
else
this.score = score;
}
}
다소 억지스러운 예제지만
score에 0이상 100이하의 숫자만 들어간다는것을 확신할 수 있게 되었다.
프로젝트가 거대해지고 코드의 양이 많아졌을 때,
getter setter함수 없이 인스턴스의 필드에 바로 접근해 값을 수정하게 되면
디버깅하기가 정말 어려워진다. (물론 참조목록들을 보며 일일이 검사하며 찾을 수 있긴 하다..... 우웩)
이때 필요한게 방금과 같은 getter / setter 패턴이다.
쓰다 보니 안 사실인데
원래 주제가 C#의 프로퍼티였으므로 다시 돌아가보자.
C#에서는 getter / setter 패턴을 위한 프로퍼티라는 특별한 기능을 제공한다.
프로퍼티의 기본 형식
private int score;
public int Score
{
get
{
return score;
}
set
{
score = value;
}
}
score라는 int형 필드를 선언했다.
그리고 Score라는 int형 프로퍼티를 선언했다.
언뜻보면 함수인지, 필드인지, 클래스인지 분간이 안되지만 자세히 보면 get, set, value라는 키워드를 가지고 있는걸 볼 수 있다.
이때 눈여겨 볼 점은 value인데 이는 예약어로 Score 프로퍼티에 대입하는 대상을 컴파일러가 알아서
value로 바꿔준다.
get,set 이들은 각각 getter / setter에 대응되며 함수처럼 작동하게 된다.
위에서 다뤘던 예제를 이번에는 getter / setter가 아닌 get,set 프로퍼티를 이용해 구현해보겠다.
class Test
{
static void Main()
{
Student a = new Student();
a.Score = 4200;
}
}
class Student()
{
private int score;
public int Score
{
get
{
return score;
}
set
{
if(value > 100)
score = 100;
else if(value < 0)
score = 0;
else
score = value;
}
}
}
완벽하게 getter / setter를 대체하고 있다.
아니.. 프로퍼티가 어떤건지는 알겠는데 그냥 getter / setter 써도 되는거 아닌가요? 코드 길이도 비슷해보이는데
이게 끝이 아니다.
프로퍼티는 무려 필드처럼 사용할 수 있다.
자동 구현 프로퍼티라는걸 사용하면 되는데, 사용 예제는 다음과 같다.
class Student
{
public int Score // Score는 마치 필드처럼 동작한다.
{
get;set;
}
}
이는 마치 Student가 score라는 int형 필드를 가지고 있는것과 같은 효과를 낸다,
또한
class Student
{
public int Score = 0; // Score는 초기값을 가지며 마치 필드처럼 동작한다.
{
get;set;
}
public int Age {get;} // Age는 읽기 전용이다.
}
선언과 동시에 초기화를 수행할 수 있으며, get만 추가하여 읽기 전용으로 만들 수 있다.
마지막으로, 프로퍼티를 이용하여 객체를 생성할 때 필드 초기화도 할 수 있다.
class Test
{
static void Main()
{
Student a = new Student() // 프로퍼티를 이용한 필드 초기화
{
Score = 80
};
}
}
class Student()
{
private int score;
public int Score
{
get
{
return score;
}
set
{
if(value > 100)
score = 100;
else if(value < 0)
score = 0;
else
score = value;
}
}
}
결론
C#의 프로퍼티는 OOP의 기본 개념인 getter / setter를 보다 편리하게 구현하고,
프로퍼티 자체를 함수처럼 쓸 수 있으며
나아가 직접 인스턴스의 필드까지 될 수 있는 강력한 기능이다.
'etc > C#' 카테고리의 다른 글
[C#] Lambda Function Capture (1) | 2021.07.30 |
---|---|
[C#] switch 제어문 (0) | 2021.07.16 |
[C#] 문자열 보간(Interpolation) (0) | 2021.07.15 |
[C#] Null-Safety를 지원하는 C# (0) | 2021.07.13 |
[C#] Lambda Expression(람다 식) 이란? (0) | 2021.07.12 |