프로퍼티 정의 및 역할
프로퍼티 혹은 속성(Property)은 클래스나 구조체의 필드에 안전하게 접근하고 값을 설정하기 위한 캡슐화된 메커니즘이다. 속성은 외부에서는 필드처럼 보이지만, 내부적으로는 메소드처럼 동작한다.
| 구분 | 설명 |
|---|---|
| 정의 | 필드의 값을 읽거나 쓰기 위해 사용되는 get 및 set 접근자를 포함하는 함수 멤버이다. |
| 주요 역할 | 캡슐화를 유지하며, 필드를 private 지정자로 선언하여 외부의 직접 접근을 막고, 속성을 통해 유효성 검사 등 필요한 로직을 추가하여 접근을 제어한다. |
| 구현 방식 | 내부적으로는 메소드이지만, 외부에서는 필드처럼 = 연산자를 통해 접근한다. |
프로퍼티 기본 구조
일반적으로 데이터를 저장하는 전용 필드(Private Backing Field)와 이를 제어하는 접근자 블록으로 구성한다.
private int myAge; // 전용 필드(Private Backing Field)
public int Age // 프로퍼티 선언
{
get // get 접근자: 값을 읽을 때 호출된다.
{
return myAge;
}
set // set 접근자: 값을 쓸 때 호출된다.
{
if (value < 0) // 유효성 검사 로직 추가 가능
{
myAge = 0;
}
else
{
myAge = value; // 'value' 키워드는 할당된 값(우변 값)을 나타낸다.
}
}
}
접근자 블록을 정의하여 프로퍼티의 기능을 제한할 수 있다.
| 프로퍼티 형태 | 특징 |
|---|---|
| 읽기/쓰기 | get 및 set 접근자 모두를 가진다. |
| 읽기 전용 | get 접근자만 가지며, 외부에서 값을 읽을 수만 있다. |
| 쓰기 전용 | set 접근자만 가지며, 외부에서 값을 설정할 수만 있다. |
자동 구현 프로퍼티
필드에 별도의 유효성 검사 로직이 필요하지 않고 단순히 값을 저장 및 조회만 할 경우에는 코드를 간결하게 작성할 수 있는 기능이다.
// 컴파일러가 내부적으로 private int <ID>k__BackingField; 를 생성한다.
public int ID { get; set; }
- 원리: 컴파일러가 자동으로 private 전용 필드를 생성한다. 따라서 개발자는 필드를 명시적으로 선언할 필요가 없다.
람다 표현식 프로퍼티
속성의 get 접근자가 단일 표현식으로만 이루어져 있다면, 코드를 더 간결하게 람다 표현식 형태로 작성할 수 있다.
// 일반 get 접근자
public string FullName
{
get { return $"{FirstName} {LastName}"; }
}
// 람다 표현식 프로퍼티
public string FullName => $"{FirstName} {LastName}";
무명 타입
무명 타입(Anomymous Type)은 컴파일러가 이름 없이 자동으로 타입을 생성하는 기능으로, 일반적으로 데이터의 임시 컨테이너로 사용된다.
| 구분 | 설명 |
|---|---|
| 정의 | new 키워드와 객체 초기화 구문을 사용하여 정의되지만, 타입 이름은 명시하지 않는다. |
| 타입 추론 | 컴파일러가 초기화된 속성들의 이름과 타입을 기반으로 해당 무명 형식의 타입을 자동으로 추론한다. |
| 특징 | 1. 모든 속성은 읽기 전용이다. 2. 주로 LINQ 쿼리의 결과 셋에서 데이터를 임시로 저장하고 전달할 때 사용된다. |
| 변수 선언 | 타입을 명시할 수 없으므로, 변수를 선언할 때는 var 키워드를 사용하여 컴파일러에게 타입 추론을 맡긴다. |
무명 타입의 예시 코드는 다음과 같다.
// 컴파일러가 내부적으로 이름과 나이 프로퍼티를 가진 새 타입을 정의한다.
var user = new { Name = "Alice", Age = 30, IsActive = true };
Console.WriteLine(user.Name); // Alice
// user.Name = "Bob" // 무명 타입의 프로퍼티는 읽기 전용이다.
프로퍼티 사용 이점
프로퍼티 사용 이점에는 유효성 검사, 느슨한 결합, 읽기/쓰기 제어 등이 있다.
-
유효성 검사: set 접근자에 값을 할당하기 전 유효성 검사 로직을 넣어 데이터의 무결성을 보장할 수 있다.
-
느슨한 결합: 외부 코드는 필드에 직접 접근하지 않고 속성이라는 통로를 사용하므로, 내부 필드 구현이 바뀌어도 외부 코드를 수정할 필요가 없다.
-
읽기/쓰기 제어 private set 이나 protected get 등을 사용하여 접근 권한을 필드마다 다르게 설정할 수 있다.