어떤 클래스의 필드를 외부에서 Read / Write하는 방법에는 여러가지가 있다.
가장 쉬운 방법은 아래 코드와 같이 해당 필드를 public으로 설정하는 것이다.
class People
{
public int age = 0;
}
하지만, 내부 필드를 public으로 선언해놓는 것은 매우 위험할 수 있다. 예를들어, 나이를 나타내는 age 변수의 경우 '음수가 될 수 없다'라는 조건이 필요할 수 있다. 이러한 상황에서 public으로 되어 있기 때문에 외부 접근자에 의해서 음수가 될 가능성이 충분하다.
두번째 방법은 Getter / Setter를 두는 방법이다. 내부변수를 private나 protected와 같은 외부에서 접근할 수 없는 제한자를 두고 Getter / Setter에 해당하는 함수를 구현하는 방법이다.
값에 대한 조건을 제한할 수 있다는 장점이 있지만 모든 필드에 하나씩 함수를 구현하는 것은 코드 구현량이 많아질 수 있다.
class People
{
private int age = 0;
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
}
C#에서는 이를 위해 Property라는 기능을 지원한다. Property를 정의할 때 Getter에 해당하는 Get-Property와 Setter에 해당하는 Set-Property를 쉽게 정의할 수 있다.
Get-Property에서는 값을 반환하기 전에 특정 필드에 대한 가공처리가 가능하고, Set-Property에는 필드에 값을 대입하기 전에 전달받은 값을 가공할 수 있다. Set에서 value 키워드를 통해 전달받은 값을 처리할 수 있다.
class People
{
private int age = 0;
public int Age
{
get { return age; }
set { age = value; }
}
}
class Program
{
public static void Main(string[] args)
{
People p = new People();
p.Age = 10; // set 호출
int n = p.Age; // get 호출
}
}
Property를 사용할 때의 가장 큰 장점 중 하나는 Property를 정의하는 방식은 함수를 정의하는 방식이지만 사용하는 방식은 필드를 사용하는 방식이라는 것이라고 생각한다.
위의 예제에서 p.Age를 보면 같은 키워드지만 어디에 사용되는지에 따라 get이 호출되는지 set이 호출되는지 달라지는것을 알 수 있다.
컴파일러가 Property를 보면 자동으로 함수를 생성해주고 사용될 때 함수를 호출하는 방식으로 동작한다고 한다.
get, set의 접근 제한자를 변경할 수 있다.
읽기/쓰기 전용 속성을 만드는 것이 가능하다.
class People
{
private int age = 0;
public int Age
{
get { return age; }
private set { age = value; }
}
}
Backing 필드가 없는 속성을 만들 수 있다.
class People
{
public bool IsAdult
{
get { return age > 20; }
}
}
Indexer는 객체를 배열처럼 사용할 수 있게 하는 방법이다. 아래 코드예제는 문장을 의미하는 Sentence 클래스에 문자열 배열이 있는 예제이다.
Sentence에 인덱스 접근을 하고자 하지만 접근할 방법이 없어 컴파일 에러가 발생하는 상황이다.
class Sentence
{
public string[] words;
public Sentence(string s) { this.words = s.Split(); }
}
class Program
{
public static void Main(string[] args)
{
Sentence s = new Sentence("Coffee is Free!");
s[0] = "Water"; // Error!
}
}
Sentence에 대해 인덱스 접근을 위해 Indexer를 정의할 수 있다. 정의하는 방법은 Property와 유사하다. Property이름 대신에 this와 매개변수 형식을 적으면된다.
class Sentence
{
string[] words;
public Sentence(string s) { this.words = s.Split(); }
public string this[int idx]
{
get { return words[idx]; }
set { words[idx] = value; }
}
}
class Program
{
public static void Main(string[] args)
{
Sentence s = new Sentence("Coffee is Free!");
s[0] = "Water"; // Ok!
}
}
Indexer는 매개변수를 가지는 Property라고 할 수 있다. 2개 이상의 Index를 넣을 수 있고 Index의 자료형 또한 자유롭게 사용할 수 있다.