언어/C#

C# 속성 (Property) - 1. 속성, 매개변수 없는 속성

tsyang 2020. 12. 20. 13:36

속성 (property)


 

속성은 메서드를 소스 코드상에서 호출하는 방법을 단순하게 만들어준다. CLR은 흔히 속성이라고 이야기하는 매개변수 없는 속성과 매개변수가 있는 속성 (C#에서는 인덱서)를 지원한다. 

 

 

 

매개변수 없는 속성


 

객체지향에서 중요한건 데이터 캡슐화이다. 클래스에서 정의한 필드가 외부에 노출되지 않도록 하여 필드의 상태 보호하는 것이다. 예를 들어,

        Person p = new Person();
        p.Age = -1; //나이가 음수?

위와 같은 코드는 쉽게 필드의 상태를 훼손시킨다. 

 

뿐만 아니라, 값을 캐쉬에 보관하거나, 내부 객체를 지연생성 하거나 쓰레드 안정적으로 접근해야 하는 경우에도 데이터 캡슐화를 하는게 중요할 수 있다.

 

따라서 타입을 설계할 때는 모든 필드를 가능한 private으로 선언하는것이 강력히 권고된다. 그 후에 다른언어의 접근자 메서드 (Accessor Method) 즉, 흔히 게터(getter) 세터(setter)라 불리는 애들을 갖다 쓰는게 좋다. 

 

그러나 이런 접근자 메서드는 코드상에서 필드보다 복잡한 문법을 호출해야 하기 때문에 사소한 불편함이 생길 수 있는데 이때문에 CLR은 속성이라는 메커니즘을 통하여 이러한 불편함을 해소하려 한다.

 

    public sealed class Person
    {
        private string m_Name;

        public string Name
        {
            get { return m_Name; }
            set { m_Name = value; } //value는 새로운 값이나 참조를 가리킴.
        }
    }

    public static void Main()
    {
        var p = new Person();
        p.Name = "Poky";
        Console.WriteLine(p.Name);  //마치 필드처럼 쓸 수 있다.
    }
    

 

더 나아가 CLR은 정적, 인스턴스, 추상, 가상 속성을 지원한다. 또 모든 접근 제한자와 함께 사용될 수 있으며 인터페이스에서도 정의될 수 있다.

 

 

컴파일러는 Name 속성을 보고 두개의 메서드 - get과 set 메서드를 자동으로 생성한다. 

 

        public String get_Name()
        {
            return m_Name;
        }

        public void set_Name(String value)
        {
            m_Name = value;
        }

 

따라서 Person 클래스 내부에 프로그래머가 저 위의 메서드들을 정의한다면 

 

이런 오류가 발생하게 된다. Name 프로퍼티를 정의한 순간 set_Name과 get_Name 이라는 이름의 메서드를 예약하기 때문이다.

 

 

 

자동 구현 속성


 

속성을 필드를 캡슐화할 목적으로만 사용하는 경우를 위해 자동 구현 속성을 정의할 수 있다.

 

    public sealed class Person
    {
        public string Name { get; private set; }
    }

이렇게 되면 C#의 컴파일러는 자동으로 속성과 연결되는 private 필드를 정의해준다.

 

자동 구현 속성은 편리하지만 다음을 고려해야 한다.

 

  1. 자동 구현 속성을 이용하면 값을 초기화할 수 있는 방법이 없다. 따라서 초기값을 대입하려면 명시적으로 생성자에서 각각의 자동 구현 속성마다 값을 초기화해줘야 한다.
  2. 런타임 Serialization 엔진은 스트림에 객체를 serialize할 때 필드의 이름에 의존한다. 자동 구현 속성이 생성하는 필드의 이름은 컴파일러가 임의로 정의하기에 코드를 컴파일 할 때 필드이 이름이 바뀌게 되어 스트림으로부터 값을 복원할 수 없는 경우가 생길 수 있다. 따라서 serialize가 필요한 타입을 만든다면 자동 구현 속성은 사용하지 말아야 한다.
  3. 디버깅할 때 get과 set메서드에 중단점을 추가할 수 없다

 

 

주의사항


 

속성은 마치 필드에 접근하는 코드처럼 보이기 때문에 개발자들에게 혼란을 야기할 수 있다. 속성의 유일한 장점은 단순화된 문법을 사용할 수 있다는 점 뿐이다. 성능상의 이점이 있는것도 아니고 코드에 대한 이해가 발생할 가능성도 높다. 

 

그럼에도 속성을 사용하고자 한다면 다음을 고려해야 한다

 

  • 속성 메서드는 실행하는 데 시간이 오래 걸릴 수 있지만 필드에 대한 접근은 언제나 신속하다. 스레드 동기화를 위해 속성을 사용하는 것은 아주 일반적인 사용 예인데, 이 경우 스레드가 영원이 중단될 수 있다. 따라서 스레드 동기화가 필요한 겨웅라면 속성을 쓰지 말고 메서드를 쓰는게 더 적절할 수 있다. 특히 MarshalByRefObject 를 상속하는 경우 속성을 절대로 쓰지 말아야 한다. (이게 뭐임)
  • 만약 속성을 한 줄에서 여러 번 호출하면 매번 다른 값을 반환하지만 필드는 그렇지 않다. 이런 동작은 오류를 발생시킬 수 있다. 특히 System.DateTime 클래스의 읽기 전용 속성 Now는 매번 조회할 때 마다 다른 값을 준다. 이런 동작은 잘못 된 것이다. (캐싱해서 써야할듯)
  • 속성의 값을 설정하는 순서를 변경한다 하더라도 일관되게 동작하도록 설계해야 한다.

 

'언어 > C#' 카테고리의 다른 글

C# 이벤트  (1) 2021.01.02
C# 속성 (Property) - 2  (0) 2020.12.27
C# 매개변수  (0) 2020.12.13
C# - @ (verbatim identifier)  (2) 2020.12.07
C# 메서드 - 3. 확장 메서드  (1) 2020.11.28