본문 바로가기
프로그래밍/C#

C# 업그레이드된 자동 구현 속성(Auto-Implement Property)에 대해서

by bantomak 2024. 12. 29.
반응형

C# 속성(Property)

C# 1에서는 언어 차원에서 속성을 구현할 때 사용할 수 있는 추가적인 기능이 거의 없었다. 각각의 속성별로 속성을 저장하기 위한 지원 필드(backing field), 게터(getter), 세터(setter)등을 모두 수동으로 구현했음을 알 수 있다.

 

public class Point
{
    private double x, y;
    public double X { get { return x; } set { x = value; } }
    public double Y { get { return y; } set { y = value; } }
}

C# 3에 이르러서야 자동 구현 속성이라는 기능이 추가되었다.

 

public class Point
{
    public double X { get; set; }
    public double Y { get; set; }
}

C# 3에서 수동으로 구현한 읽기 전용 속성을 포함하는 Point 클래스

C# 3에서는 읽는 동시에 쓸 수 있는 속성만 자동 구현 속성으로 선언할 수 있었다. Point와 같은 불변 클래스로 선언했을 때 다양한 장점이 있다. 그러자면 속성을 읽기 전용으로 선언해야 하는데, 이 경우 자동 구현 속성 기능을 사용할 수 없으므로 수동으로 코드를 작성해야 했다.

 

public class Point
{
    private readonly double a;
    private readonly double b;

    public double OpenA { get { return a; } }
    public double OpenB { get { return b; } }

    Point(double a, double b)
    {
        this.a = a; // 생성시 필드값 초기화
        this.b = b;
    }
}

C# 3의 자동 구현 속성에 private 세터를 선언하여 외부에서는 읽기만 가능하도록 속성을 구현한 Point 클래스

이처럼 코드를 작성해도 그럭저럭 동작은 하겠지만, 우리가 원하는 것을 정확히 표현하진 못했다. 어떤 경우라도 속성이 변경되는 것을 허용하고 싶지 않겠지만 이 경우에는 클래스 내부에서라면 얼마든지 속성을 변경할 수 있기 때문이다.

 

public class Point
{
    public double X { get; private set; }
    public double Y { get; private set; }

    Point(double x, double y)
    {
        this.X = x;
        this.Y = y;
    }
}

자동 구현 속성 초기화

C# 6 이전에는 자동 구현 속성에 대한 초기화를 반드시 생성자 내에서만 수행할 수 있었으며, 속성을 선언하는 시점에 함께 초기화할 수는 없었다. 예를 들어 C# 2로 개발된 Person이라는 클래스가 있다고 해보자.

public class Person
{
    private List<Person> friends = new List<Person>(); // 필드 선언 및 초기화
    public List<Person> Friends // 필드 값 읽고 쓰는 속성 노출
    {
        get { return friends; }
        set { friends = value; }
    }
}

 

해당 코드를 자동 구현 속성을 이용하여 재작성하고 싶다면 필드 초기화 부분을 생성자 내부로 옮겨야 한다. 그런데 이 코드에는 어떤 생성자도 없으므로 결국 코드를 다음과 같이 수정할 수밖에 없다.

 

public class Person
{
    private List<Person> Friends { get; set; }

    public Person()
    {
        Friends = new List<Person>();
    }
}

C# 6에서는 이러한 제약 사항이 제거되어 다음 코드처럼 속성을 선언할 때 초기화를 함께 수행할 수 있도록 개선되었다.

C# 6에서 읽기 전용 자동 구현 속성을 포함하는 Person 클래스 선언

public class Person
{
    private List<Person> Friends { get; set; } = new List<Person>();
}

당연히 해당 기능은 읽기 전용의 자동 구현 속성에도 사용할 수 있따. 자주 사용되는 패턴 중 하나로 변경 가능한 컬렉션을 노출하는 읽기 전용 속성이 있다. 이를 이용하면 사용자는 개별 항목을 컬렉션에 추가하거나 삭제할 수 있지만, 다른 컬렉션을 참조하도록 속성을 변경할 수는 없다.(null을 지정할 수도 없다). 예상대로 세터를 제거해 버리기만 하면 된다.

실제 예제

MyFriend 속성은 읽기 전용 속성이기때문에 위에서 설명한 대로 리스트에 원소를 추가하고 제거하는 것은 가능하지만 다른 리스트를 참조하도록 속성을 변경할 수는 없다.

public class Person
{
    public List<Person> Friends { get; set; } = new List<Person>();
    public List<Person> MyFriends { get; } = new List<Person>();
}


internal class Program
{
    static void Main(string[] args)
    {
        var temp = new Person();
        temp.Friends = new List<Person>();
        temp.Friends.Add(new Person());

        temp.MyFriends.Add(new Person());
        temp.MyFriends = new List<Person>(); // error
    }
}

참고 도서

 

C#을 다루는 기술 - 예스24

C#을 C#답게 사용하자!200개의 예제로 실습하며 배우는 간결하고 효과적인 C# 작성법!『C#을 다루는 기술』의 목표는 여러분이 C#을 최대한 편안하게 사용하도록 하는 것이다. C#의 주요 기능을 다

www.yes24.com

댓글