전체 페이지뷰

2016년 12월 21일 수요일

C# Property

OOP의 기본 중에 은닉성을 보장하기 위해 지금까지 우리는 마치 C++이나 자바처럼 private이나 protected 한정자로 필드를 숨기고, 이 필드에 접근하는 메소드를 public으로 공개하여 필드를 다루는 방법을 써 왔습니다. 그러나 C#에서는 좀 더 쉽게 이런 방법을 구현할 수가 있고 이것을 property라 부릅니다.


과거의 방법을 미리 살펴봅니다.
class MyClass
{
    private int myField;
    public int GetMyField(){ return myField; }
    public void SetMyField( int NewValue ) { myFeild = NewValue; }
}
cs

클래스 내부에 private으로 지정되어 외부에서 직접 접근할 수 없는 필드가 있습니다.
이 필드의 값을 받아오기 위해 GetMyField()라는 메소드와, 필드의 값을 지정하기 위해 SetMyField()라는 메소드 두 개를 따로 만들어서

MyClass obj = new MyClass();
obj.SetMyField(3);
Console.WriteLine( obj.GetMyField() );
cs
와 같이 사용합니다.
이 방법은 물론 옳은 방법이고, 지금도 쓰이고 있지만 C#에서는 저 과정을 합쳐준 프로퍼티라는 것이 존재합니다.

접근한정자 데이터형식 프로퍼티명
{
    get
    {
        return 필드이름;
    }

    set
    {
       필드이름 = value;
    }
}

와 같이 사용합니다. 여기서 get, set은 접근자(accessor)라고 불리며 우리가 지정한 적 없는 "value"라는 것은 컴파일러가 자동으로 만들어 준 매개변수명입니다.

이제 프로퍼티를 이용해서 앞서 말한 과거의 방식을 바꿔보면,
class MyClass
{
    private int myField;
    public int MyField
    {
        get
        {
            return myField;
        }
        set
        {
            myField = value;
        }
    }
}
cs

로 되고,
MyClass obj = new MyClass();
obj.MyField = 3;
Console.WriteLine( obj.MyField );
cs
로 사용합니다.

나아가 C# 3.0 부터는 의미없는 단순 노동을 줄이기 위해 자동 프로퍼티가 도입되어 get, set 뒤의 내용을 생략가능하게 했습니다.
class MyClass
{
    public int MyField
    {
        get;
        set;
    }
}
cs
필드를 선언하는 과정도 없어졌고, get, set 뒤에 그냥 세미콜론만 붙이면 컴파일러가 알아서 해줍니다.

set을 없애면 이 프로퍼티는 읽기전용이 됩니다.

이제 이 프로퍼티를 이용하는 예제를 한번 보겠습니다.

using System;
class Program
{
    class Customer
    {
        //  자동 프로퍼티 생성
        public double TotalPurchases { get; set; }
        public string Name { get; set; }
        public int CustomerID { get; set; }
        // 메소드
        public string GetContactInfo() { return "ContactInfo"; }
        public string GetTransactionHistory() { return "History"; }
    }
    class Application1
    {
        static void Main()
        {
            // 객체 초기화
            Customer cust1 = new Customer()
            {
                TotalPurchases = 4987.63,
                Name = "North wind",
                CustomerID = 90108
            };
            // 프로퍼티 수정
            cust1.TotalPurchases += 499.99;
        }
    }
}
cs

클래스 내에 세개의 자동 프로퍼티가 서술되었습니다.
그러면 이것이 그냥 public인 필드를 선언하는 것과 무엇이 다르냐는 질문이 생길지도 모르겠습니다.

사실 내부적으로는 프로퍼티를 연결해 주는 필드가 컴파일러에 의해 자동 생성되고, 프로퍼티의 get, set은 거기에 연결됩니다. 따라서 private 필드를 생성하고 거기에 연결되는 public 메소드가 생기는 과정을 컴파일러 수준에서 알아서 해 주는 것과 같은 결과를 갖습니다.

위의 메인 메소드 내에서 객체를 초기화 한 과정만 떼서 다시 한번 살펴보도록 합니다.

Customer cust1 = new Customer()
{
    TotalPurchases = 4987.63,
    Name = "North wind",
    CustomerID = 90108
};

처럼 생성했습니다.

클래스이름 인스턴스 = new 클래스이름()
{
    프로퍼티1 = 값,    // 세미콜론이 아닌 콤마로 구분합니다 
    프로퍼티2 = 값,
    프로퍼티3 = 값
};    //세미콜론으로 끝납니다

의 문법을 따릅니다.  모든 프로퍼티의 값을 초기화시에 넣어야 할 필요는 없으며, 필요한 값만 넣어주면 됩니다.

물론 클래스 내에 생성자를 만들어 초기화시에 이용하는 것도 여전히 유효합니다.
using System;
class Program
{
    class Customer
    {
        public double TotalPurchases { get; set; }
        public string Name { get; set; }
        public int CustomerID { get; set; }
        // 생성자
        public Customer(double purchases, string name, int ID)
        {
            TotalPurchases = purchases;
            Name = name;
            CustomerID = ID;
        }
        
        public string GetContactInfo() { return "ContactInfo"; }
        public string GetTransactionHistory() { return "History"; }
    }
    class Application1
    {
        static void Main()
        {
            Customer cust1 = new Customer(4987.63"Northwind"90108);
            cust1.TotalPurchases += 499.99;
        }
    }
}
cs


익명형식

익명 형식은 명시적으로 형식을 지정할 필요없이 읽기 전용의 인스턴스를 만듭니다.
읽기 전용이므로 프로퍼티의 값 수정은 불가하며 인스턴스를 한번만 만들 수 있습니다.

var v = new { Amount = 108, Message = "Hello" };  
Console.WriteLine(v.Amount + v.Message);  
cs

보시다시피 클래스 정의 없이  var형을 사용하여 v라는 변수를 만들고, 거기에 Amount와 Message라는 프로퍼티를 설정해서 사용합니다.

일반적으로 이 익명형식은 나중에 공부할 LINQ에서 유용하게 사용됩니다.

인터페이스의 프로퍼티

앞서 인터페이스는 메소드만이 아니라 프로퍼티, 인덱서도 가질 수 있다고 설명했습니다.
인터페이스에서 프로퍼티를 사용할 때는 약간 특이한 점이 있습니다.
인터페이스에는 메소드명만 들어갈 뿐 구현을 갖지 않는다고 했습니다.
프포퍼티에 따라오는 get; set;도 사실 간소화된 메소드라 할 수 있는데,
get; set; 자동구현 프로퍼티는 원래 구현부를 갖지 않으므로 인터페이스의 선언과 상속받은 클래스의 자동 구현의 모습이 같다는 점입니다.

interface IEmployee
{
    string Name
    {
        get; set;
    }
    int Counter
    {
        get;
    }
}
public class Employee : IEmployee
{
    public string Name  // 읽기-쓰기
    {
        get; set;      
    }
    public int Counter  // 읽기전용
    {
        get;
    }
}
cs

추상클래스의 프로퍼티

역시 인터페이스와 마찬가지입니다.
다만 프로퍼티 역시 "abstract" 한정자로 수식해준다는 점만 유의하면 되겠습니다.

댓글 없음:

댓글 쓰기