C# 프로퍼티 사용하는 이유

객체지향의 관점에서 엄밀히 따졌을 때 전자는 프로퍼티이고, 후자는 필드입니다.

C# 컴파일러에서는 둘을 같은 코드로 취급합니다. 이 경우 둘 모두 프로퍼티입니다.

결국 관점에 따라 다른 문제인데, 어차피 같은 코드라면 이러나 저러나 별 차이가 없다고 볼 수도 있고, 객체지향을 중시한다면 해당 표현에 차이가 있다고 볼 수도 있습니다.

4 Likes

프로퍼티를 사용하면 해당 변수를 입출력 할 때 좀 더 세밀하게 표현할 수 있죠.

public int age {
    get { return age; }
    set {  age = (value < 0) ? 0 : value; }
}
1 Like

auto getter setter를 사용할건지 그냥 필드를 사용할건지는 취향 차이입니다.

2 Likes

저도 처음에 헷갈려서 많이 검색하곤 했는데
auto property는 아래 코드를 한방에 적을 수 있게 해주는 단축키입니다.

private string age;
public string Age {
    get {
        return age;
    }
    set {
        age = value;
    }
}  

필드를 직접적으로 노출하지 않고 이렇게 property를 통해 간접적으로 노출하는 것은 객체지향의 철학과 연관이 있습니다. 저도 처음에 같은 코드인데 왜 이렇게 하는지 의문을 가졌으나 객체지향관련해서 수업을 들으면서 차이점을 알게 됐습니당.

예전에 제가 검색해서 정리한 property 쓰는 몇 가지 이유와 필드와 차이점들입니다.

  1. 일종의 Interface의 역할?

어떤 필드를 나중에 Getter Setter로 바꾸게 되면 그 필드를 사용하고 있었던 코드를 다 수정해야 합니다. 애초에 Getter Setter로 사용할 가능성이 높은 값들은 auto property로 미리 만들어 놓으면 이런 상황을 방지할 수 있습니다.

  1. 세밀하게 접근 제어자를 사용할 수 있습니다.
    읽기만
    public int Age { get; private set; }
    쓰기만
    public int Age { private get; set; }
  2. 필드와 property의 차이점들이 있습니다.

예를 들어서,

필드는 함수 인자로 out이나 ref로 전달할 수 있지만 property는 필드가 아니라서 당연히 안 됩니다.

property를 사용하면 Getter Setter가 내부적으로 만들어지기 때문에 함수처럼 Getter Setter를 override할 수 있습니다.
부모 클래스
public virtual int Age { get; set; }
자식 클래스
public override int Age { get { return 자식클래스의반환방식; } }

3 Likes

프로퍼티를 사용하는 이유는 단순합니다.
첫번째 이유는 데이터에 접근을 힘들게 하기 위해서죠.
악용한다면 public int a; 의 경우는 쉽게 접근할 수 있지만 get,set로 접근을 어렵헤 하는 거죠
두번째 이유는 디버깅 때문입니다.
get,set 을 만들어 놓으면 안에 중단점을 찍어 해당 변수가 사용될 때마다 체크할 수 있습니다.

흐음… 몇가지 정정할 필요가 있는 내용들 조금 끄적거려 봅니다.

내부 동작 관련

우선 C#에서 property와 field는 다르게 처리 됩니다. 질문자분께서 문의주신 형태로 암묵적 프로퍼티 표현식을 사용하게 될 경우, 해당 instance에 자동으로 private backing field가 생성 됩니다. 그리고 암묵적 getter/setter는 자동 생성 된 backing field로 연결 됩니다.

첨부 이미지를 보시면, DeclaredFields 아래에 생성 된 빨간 박스는 자동 생성된 backing field이며, class에서 선언한 B property는 DeclaredFields가 아닌 DeclaredProperties에 생성 되는것을 보실 수 있습니다.

Property는, 실제 코드로서는 getter/setter method를 생성시킵니다. 작성하는 코드에서는 마치 field처럼 사용하지만, 실제로는 method를 호출하게 됩니다. 해당되는 method 내에서는 다시, 앞서 자동 생성된 backing field를 return 하는 동작을 수행 하게 됩니다.

public int Age { get; set; } 의 정의 관련

사실 이 내용은 앞서 다른분들께서 정리를 잘 해주셔서, 굳이 객체지향 혹은 캡슐화 관점의 설명은 생략
하겠습니다.

다만, getter / setter 두가지 모두 암묵 표현으로 사용하는 문화는, 사실 C#이 참조 한 언어인 JAVA로부터 물려오는, 약간은 복잡한 히스토리를 가지고 있는 내용 입니다. JAVA를 사용하는 개발 팀 혹은 회사마다 룰이 조금씩은 다를 수 있겠으나, 단순하게 public field로 사용 할 수 있는 멤버 변수도 반드시 getter/setter를 강제하는 코딩 룰을 유지하는 그룹이 꽤 있습니다. 차후, 해당 멤버 변수 access 방법론이 변경 될 경우, 단순 멤버 변수를 노출 해놓은 모형보다는 조금 더 일관된 수정 방법을 사용 할 수 있기에 의미는 있다 볼 수 있습니다.

안타깝긴 하지만, 이와 관련 된 내용으로 수년간 박터지게 싸우는 스레드를 어렵지 않게 찾을 수 있습니다. 심심하실때 팝콘 들고 찾아 읽으셔도 꽤나 재미있습니다.

제 경우에는, C#을 사용하는 개발 팀 혹은 회사에서는 적어도 property 강제 코딩 룰을 가진 그룹은 만난적이 없기는 합니다. 적어도 C#에서는, 암묵적인 getter와 암묵적인 setter를 각각 선언 할 수 있어야하므로, 두가지 동시 암묵선언을 하는 표현식이 허용 되어 있다 (굳이 안막았다) 정도로 이해를 하시는게 어떨까 합니다.

public int Age { get; set; } 의 활용 관련

사실, getter / setter를 property라는 개념으로 잘 구현해준 C#에서는, 이를 활용 할 수 있는 방법이 무궁무진합니다. 태생은 앞서 말씀드린대로 getter / setter에 그 목적이 있는것이 맞으나, 워낙 RTTI가 잘 구현된 C# 특성 덕에, reflection을 활용하여 기능 구현을 하는 라이브러리들이 꽤 많습니다.

대표적으로, Serializer (Newtonsoft.Json, fastJSON, …)와 Entity Framework같은것들을 예로 들 수 있겠습니다. 대부분의 Serializer 라이브러리들은 class의 property를 추출 대상으로 인지합니다. field나 method를 사용 할 수 없는것도 아닙니다만, 대부분의 Serialize 라이브러리들은 암묵적으로 약속이 된것 마냥 property를 사용 합니다. Entity Framework 또한 model scheme 정의를 위하여 property를 사용 합니다. 물론 field를 활용 할 수도 있기는 하지만 옵션을 통하여 명시적 선언을 해주어야 합니다.

위와같은 library들은, 단순히 field인지 property인지를 기준으로 대상 값을 찾습니다. 조금 특수한 처리를 해야 할 경우 property를 조금 더 복잡하게 사용 할 수 있겠지만, 단순 선언의 경우 질문자 분께서 문의 주신 표현식과 동일하게, public {type} {name} { get; set; } 형태로 선언을 하게 됩니다. 말 그대로, property가 추출 조건이니 property로 정의만 되면 되기에 최소 표현식을 활용 합니다.

저 또한, 런타임에 DLL을 로딩하여 노출되는 class의 속성을 옵션으로 받아야 하는 솔루션 제작에서 property를 위와같은 방식으로 구현/활용하여 진행 한 기억이 있네요.

제 답변이 조금 길어 요약을 하자면,

C#의 property는 그 태생상 목적과 이유, 그리고 현주소에서의 활용법을 분리하여 생각하면 이해에 도움이 된다 입니다.