CS/C#

[C#] property, 프로퍼티

Mirab 2021. 12. 21. 22:41

오늘은 프로퍼티에 대해서 배워보겠습니다.

기존에 C++을 공부를 했었고, 은닉성을 위해서는 public으로 필드 멤버를 선언하는 것이 아닌 private로 감추고

필요한 부분만 getter, setter를 구현해서 사용하라고 배웠습니다.

맞는 방법이지만 한 변수에 getter와 setter까지 하면 변수가 많아질수록 이 수 또한 엄청 많아지게 될 것입니다.

C#에서는 이러한 것들을 한 뭉치로 묶을 수 있는 프로퍼티를 제공합니다!

 

# 프로퍼티

class Program
{
    private int age;
    public int Age
    {
        get { return age; }
        set { age = value; }
    }
}

age라는 것을 Age라는 프로퍼티로 제공하게 됩니다.

Program p = new Program();
p.Age = 5; // 쉬운 setter
Console.WriteLine(p.Age); // 쉬운 getter

위와 같은 방식으로 쉽게 쓰고 대입할 수 있습니다.

 

좀 더 만들어봅시다.

using System;

namespace Property
{
    class BirthdayInfo
    {
        private string name;
        private DateTime birthday;

        public string Name // 프로퍼티!
        {
            get { return name; }
            set { name = value; }
        }

        public DateTime Birthday
        {
            get { return birthday; }
            set { birthday = value; }
        }

        public int Age
        {
            get
            {
                return new DateTime(DateTime.Now.Subtract(birthday).Ticks).Year;
            }
        }
    }

    class Program
    {
        static void Main()
        {
            BirthdayInfo birth = new BirthdayInfo();
            birth.Name = "지코";
            birth.Birthday = new DateTime(1992, 9, 14);

            Console.WriteLine($"Name : {birth.Name}");
            Console.WriteLine($"Birthday : {birth.Birthday.ToShortDateString()}");
            Console.WriteLine($"Age : {birth.Age}");
        }
    }
}

# 자동 구현 프로퍼티 (Auto-Implemented-Property)

위의 프로퍼티도 매력적이지만 좀 더 줄일 수 있습니다.

class Program
{
    private int age;
    public int Age { get; set; }
}

이렇게 작성하면 단순히 age를 읽고 쓰는 기능이기 때문에, C# 컴파일러가 자동으로 프로퍼티를 구현해줍니다.

 

C# 7.0부터는 자동 구현 프로퍼티 선언과 동시에 초기화도 가능하게 지원합니다.

class Program
{
    private int age;
    public int Age { get; set; } = 10;
}

자동 구현 프로퍼티의 선언과 동시에 초기화하는 예제를 연습해봅시다.

using System;

namespace AutoImplementedProperty
{
    class BirthdayInfo
    {
        public string Name { get; set; } = "UnKnown";
        public DateTime Birthday { get; set; } = new DateTime(1, 1, 1);
        public int Age
        {
            get
            {
                return new DateTime(DateTime.Now.Subtract(Birthday).Ticks).Year;
            }
        }
    }

    class Program
    {
        static void Main()
        {
            BirthdayInfo birth = new BirthdayInfo();
            Console.WriteLine($"Name : {birth.Name}");
            Console.WriteLine($"Birthday : {birth.Birthday.ToShortDateString()}");
            Console.WriteLine($"Age : {birth.Age}");

            birth.Name = "지코";
            birth.Birthday = new DateTime(1992, 9, 14);
            Console.WriteLine($"Name : {birth.Name}");
            Console.WriteLine($"Birthday : {birth.Birthday.ToShortDateString()}");
            Console.WriteLine($"Age : {birth.Age}");
        }
    }
}

 

# 자동 구현 프로퍼티의 뒷단

자동 구현 프로퍼티가 우리에게 편리함을 가져줍니다.

class Program
{
    //private int age; 이걸 쓰지 않아도 알아서 컴파일러가 뒷단에서 구현해줍니다.
    public int Age { get; set; } = 10;
}

기존에는 private로 age를 만들고 앞에 Age로 프로퍼티를 지원했지만, 그냥 Age 프로퍼티만 선언한다면 C# 컴파일러가 자동으로 구현해줍니다. 이것 때문에 우리는 좀 더 편안한 프로그래밍이 가능해집니다.

 

# 프로퍼티와 생성자

기존에 클래스는 클래스를 생성하면서 안에 멤버 필드를 초기화하고 싶다면 생성자를 만들어서 사용했습니다. 그런데 프로퍼티가 등장으로 객체를 생성할 때 각 필드를 초기화하는 또 다른 방법이 있습니다.

 

Name과 Birthday는 각각의 string과 DateTime의 프로퍼티입니다.

객체를 생성할 때 각각의 프로퍼티를 초기화하는 과정입니다.

초기화하고 싶은 프로퍼티만 사용할 수 있습니다.

BirthdayInfo birth = new BirthdayInfo()
{
    Name = "지코",
    Birthday = new DateTime(1992, 9, 14)
};
using System;

namespace ConstructorWithProperty
{
    class BirthdayInfo
    {
        public string Name { get; set; }
        public DateTime Birthday { get; set; }
        public int Age
        {
            get
            {
                return new DateTime(DateTime.Now.Subtract(Birthday).Ticks).Year;
            }
        }
    }

    class Program
    {
        static void Main()
        {
            BirthdayInfo birth = new BirthdayInfo()
            {
                Name = "지코",
                Birthday = new DateTime(1992, 9, 14)
            };

            Console.WriteLine($"Name : {birth.Name}");
            Console.WriteLine($"Birthday : {birth.Birthday.ToShortDateString()}");
            Console.WriteLine($"Age : {birth.Age}");
        }
    }
}

 

# 초기화 전용(Init-Only) 자동 구현 프로퍼티

기존에 초기화한 필드를 다시 바꾸려는 것을 막는 키워드가 있었습니다.

예를 들어서 readonly처럼 한 번 초기화하면 다음 변경을 막아버리는 키워드가 그 예시입니다.

 

프로퍼티도 이러한 기능을 지원합니다.

    class Transaction
    {
        public string From { get; init; }
        public string To { get; init; }
        public int Amount { get; init; }

        public override string ToString()
        {
            return $"{From,-10} -> {To,-10} : ${Amount}";
        }
    }

init 접근자는 set 접근자처럼 외부에서 프로퍼티 변경할 수 있지만 객체를 초기화할 때만 프로퍼티 변경이 가능하다는 점입니다. 이렇게 선언한 프로퍼티를 초기화 전용 자동 구현 프로퍼티라고 합니다.

using System;

namespace InitOnly
{
    class Transaction
    {
        public string From { get; init; }
        public string To { get; init; }
        public int Amount { get; init; }

        public override string ToString()
        {
            return $"{From,-10} -> {To,-10} : ${Amount}";
        }
    }

    class Program
    {
        static void Main()
        {
            Transaction tr1 = new Transaction { From = "Alice", To = "Bob", Amount = 100 };
            Transaction tr2 = new Transaction { From = "Bob", To = "Charlie", Amount = 50 };
            Transaction tr3 = new Transaction { From = "Charlie", To = "Alice", Amount = 50 };

            Console.WriteLine(tr1);
            Console.WriteLine(tr2);
            Console.WriteLine(tr3);
        }
    }
}

각 트랜잭션은 객체를 생성할 때 각 프로퍼티를 초기화하고, 그 이후부터는 읽기 전용으로 사용하고 있습니다.

 

오늘은 프로퍼티가 왜 나오게 됐는지, 어떻게 사용하는지에 대해서 배웠습니다.