1. 소개
필드를 직접 사용할 때 생기는 문제부터 시작해보자. 만약 네가 public으로 필드를 선언하면, 프로그램 어디서든 바로 값을 바꿀 수 있어:
public class Dog
{
public string Name;
}
Dog dog = new Dog();
dog.Name = ""; // O_o ... 이건 "강아지 이름 = 빈 문자열"이란 뜻이야!
사용자가 Name 필드에 말도 안 되는 값을 넣을 수 있어. 예를 들면, 빈 문자열, 너무 긴 이름, 아니면 null 같은 거. 이건 마치 누군가 네 새 IKEA 옷장을 조립하는데, 네가 목재 공장 전체를 마음대로 쓰게 해주는 거랑 똑같아.
참고로, 캡슐화란 객체가 자기 데이터를 스스로 관리하는 거야. 내부를 아무나 건드릴 수 없게 하고, 특별한 "문" — property(Properties)를 통해서만 접근하게 하는 거지. 이 문을 통해서 값 체크, 로그 남기기, 값 수정, 기타 반응을 추가할 수 있어.
2. 정의와 문법
Property는 클래스의 특별한 멤버로, 겉보기엔 필드랑 비슷하지만 실제로는 getter(값 가져오기)와 setter(값 설정하기)라는 두 개의 특별한 메서드로 구성돼 있어. property를 사용하면:
- 데이터 읽기/쓰기를 허용하거나 막을 수 있고,
- 데이터 접근 시 validation이나 로직을 추가할 수 있고,
- 내부 필드를 숨기거나, 값을 다른 곳에 저장할 수도 있어.
property 선언은 필드랑 비슷하지만, 중괄호와 get, set 키워드를 써.
[접근_제한자] 타입 Property이름
{
get { ... }
set { ... }
}
우리 Dog 클래스 예시를 보자:
public class Dog
{
private string _name; // 내부 필드 (private!)
public string Name
{
get { return _name; } // "getter": 이름 가져오기
set { _name = value; } // "setter": 이름 설정하기
}
}
참고: private 필드에는 보통 언더스코어(_name)를 붙여. 이게 C# 스타일 표준이야.
3. property 동작 방식
property는 객체 내부 데이터와 외부 세계 사이에 서 있는 "가드" 같은 존재야. 예시:
Dog dog = new Dog();
dog.Name = "샤릭";
Console.WriteLine(dog.Name);
설명:
- 프로그램이 dog.Name = "샤릭"; 줄에 도달하면, 이때 property의 set 메서드가 호출돼. 여기서 값이 비어있는지 등 원하는 체크를 추가할 수 있어.
- Console.WriteLine(dog.Name);에서는 get 메서드가 호출돼서 현재 값을 반환하거나, 필요하면 동적으로 계산해서 반환할 수도 있어.
겉으론 그냥 필드처럼 보이지만, 사실 내부적으로 다 컨트롤되고 있는 거지!
4. 왜 property가 "Best Practice"일까
대부분의 경우, 객체의 내부 필드에 직접 접근을 허용하지 않아. 지금은 체크가 필요 없어 보여도, 데이터를 property로 감싸는 습관이 있으면 나중에 규칙이 바뀔 때 엄청 편해.
값 할당 시 "validation" 예시:
public class Dog
{
private string _name;
public string Name
{
get { return _name; }
set
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("강아지 이름은 비어 있을 수 없어!");
}
_name = value;
}
}
}
이제 이런 코드는:
dog.Name = ""; // 예외 발생!
… 말도 안 되는 값으로부터 객체를 보호해줘.
5. property: 읽기 전용, 쓰기 전용, 일반 property
가끔은 값 읽기만 허용해야 할 때가 있어(예: 강아지의 출생 연도는 바꿀 수 없어), 또는 반대로 쓰기만 허용해야 할 때도 있어(드물지만 뭔가 신비한 걸 하고 싶을 때).
- 읽기 전용: get만 쓰고, set은 빼.
- 쓰기 전용: set만 쓰고, get은 빼.
예시:
public class Dog
{
private int _birthYear = 2018;
// 읽기 전용
public int BirthYear
{
get { return _birthYear; }
}
// 쓰기 전용 (진짜 드물어)
public string Secret
{
set { /* value로 뭔가 한다 */ }
}
}
6. property vs 필드
| 필드 | property | |
|---|---|---|
| 문법 | |
|
| 접근 | 직접 | get/set을 통해 |
| validation | 없음 | set/get에 추가 가능 |
| 확장성 | 없음 | 언제든 수정 가능 |
| IDE 통합 | 필드로 보임 | property로 보임(프레임워크에서 중요) |
그림: property 동작
sequenceDiagram
participant User as 객체 사용자
participant Dog as Dog 객체
participant Field as private 필드 _name
User->>Dog: dog.Name = "리직"
Dog->>Dog: set Name("리직")
Dog->>Field: _name = "리직"
User->>Dog: print(dog.Name)
Dog->>Dog: get Name()
Dog->>Field: _name 읽기
Dog->>User: "리직" 반환
7. 흔한 실수와 주의점
어디서 실수할 수 있는지 알아보자.
자주 하는 실수 — 필드와 property를 헷갈려서, private 데이터를 실수로 외부에 노출하는 것:
public string name; // 이건 필드야! 어디서나 보임, 위험!
이렇게 하는 게 더 좋아:
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
static property도 있는데, 모든 객체에 공통된 값을 저장할 때 써. 하지만 조심해서 써야 해.
재밌는 점: property에 get만 있고 생성자가 하나도 없으면, 값을 아예 바꿀 수 없어 — 이걸 immutable property라고 부르고, 현대 설계에서 많이 써(이건 record랑 불변 데이터 강의에서 자세히 다룰 거야).
GO TO FULL VERSION