본문 바로가기
[ Program ]/c#스터디

39.property(속성)

by 관이119 2021. 10. 9.

클래스의  맴버필드값을 직접적으로 접속해서 값을 바꾸고 값을 가져오고 하는 행위를 대신해주는 속성이라는것이 있다.

 

보통 클래스를 만들면 클래스의 맴버필드값에 따라 어떤 행위를 할지 정해주는 경우가 많은데 그렇게 하다보면 실수가 발생할수 있다.

아래 예제를 보자.

 

그림1

 

 

그림1과 같은 코드의 경우에 _dclass 의 _classcreatetime 값을 마음대로 변경해서 출력해버렸다.

최초 클래스 작성자의 의도는 그것이 아니었을텐데 이런경우 잘못된 행동을 한다고 할수 있다.

 

 

 

그림2

 

 

이런경우 그림2처럼 맴버필드는 private 으로 변경하고 속성은 get 만 놔둔다면 위와같은 문제는 발생하지 않을것이다.

이렇게 맴버필드를 숨기는걸 은닉화한다고 한다.

위와같은경우 속성대신 함수를 사용해도 충분히 같은 역할을 할수 있다.

나는 지금도 왜 함수를 놔두고 속성을 사용하는지 궁금한데 결론적으로 말하면 함수를 사용해도 똑같다.

쓰고싶은걸 쓰면 된다.

나는 항상 프로그램이 누구나 알아보기 쉽고 오류없이 빠르게 잘동작하는게 가장 좋다고 생각한다.

단지 속성을 사용하면 쓰레드를 사용할때 이벤트를 쉽게 구현이 가능한 장점이 있다.

 

 

그림3

 

 

<그림3의 소스>

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp4
{
    public partial class Form1 : Form
    {

        studyclass _sclass = new studyclass();

        public Form1()
        {
            InitializeComponent();
            Task.Run(() => changetext());
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            _sclass.studymember = textBox1.Text;
            
        }

        public delegate void labeltext(string s);
        public void changetext()
        {
            while (true)
            {
                labeltext d = (str) => label1.Text = str;
                if (label1.InvokeRequired)
                {
                    Invoke(d, _sclass.studymember);
                }
                else
                {
                    label1.Text = _sclass.studymember;
                }
            }
        }
    }

    public class studyclass
    {
        private int _studymember = 3;

        public string studymember
        {
            get
            {
                if (_studymember > 10)
                {
                    return studymember_many();
                }
                
                return $"스터디맴버는 {_studymember}명 입니다";
            }
            set 
            {
                int studymember_value = 0;
                int.TryParse(value, out studymember_value);

                _studymember = studymember_value;

            }
        }

        public string studymember_many()
        {
            return "스터디 맴버가 10 명을 초과했습니다";
        }

    }
}

 

소스가 길어져 위에 소스는 따로 붙여넣었다.

위 그림3은 텍스트 박스에 스터디 인원을 넣으면 몇명인지 표시해주고 만약 10명이 넘어갈경우 10명이 초과된다고 밑에 텍스트로 표시해주게 하는 예제이다.

 

/*

쓰레드를 아직 배우지않았지만 뭐하는건지는 알거라고 생각한다.

같은시간에(정확하게 같은시간은 아니지만) 여러개의 작업을 하는걸 멀티쓰레딩이라고 한다는정도만 알아두자.

쓰레드는 뒤에서 다시 설명할예정이다.

*/

메인쓰레드 : M쓰레드 - 프로그램이 실행되는 중심의 흐름

새로 생성한 쓰레드 :N 쓰레드 - 추가로 만들어낸 다른작업을 할수 있는 흐름

위와같이 임시로 정의하고 설명하겠다.

 

그림3은 N쓰레드 에서 M쓰레드에서 만들어진 studyclass 클래스의 객체의 _studymember 를 계속 바라보면서 해당값이 변경되는순간 N쓰레드에서 M쓰레드의 라벨값을 변경해주는 예제이다.

원래는 N쓰레드에서 M쓰레드와 위와 같이 상호작용을 해주려면 이벤트나 델리게이트를 사용하는등 복잡한 과정이 필요한데 속성만으로 해당내용을 대체할수도 있다.

만약 위예제를 함수로 만들려고하면 아주 복잡해질걸로 생각된다.

 

정리하면 속성은 맴버필드를 을 은닉할지여부를 결정할때 소스수정이 상대적으로 쉬우며 뒤에배울 쓰레드에서도 상당히 유용하게 사용할수 있다.

대부분의 책이나 설명들에서도 맴버필드를 직접노출하지말고 속성사용을 권장한다.

 

속성의 기본형태는 다음과 같다.

 

<속성예제1>

private DateTime _nowdate;

public DateTime nowdate
{
      get { return _nowdate; }
      set { _nowdate = value; } 
}

 

<속성예제2>

private DateTime _nowdate;

public DateTime nowdate
{
       get => _nowdate;
       set => _nowdate = value;
}

 

<속성예제3>

public DateTime nowdate
{
       get;set;
}

 

위예제에서 <속성예제1> 이라고 되어있는 예제가 가장 기본적인 속성형태이다.

맴버필드를 정의하고 그맴버필드의 값을 get 으로 반환할수 있게 하고 set 으로 그맴버필드값을 변경할수 있게하는것이다.

예제1의 set 에 value 라고 되있는 부분은 고정 형식인데 외부에서 받아온값이 자동으로 저 value 에 들어간다고 생각하면 된다.

즉 nowdate = Datetime.Now; 라고 해주면 value 에 Datetime.Now 가 들어간다고 생각하면 된다.

 

<속성예제2> 를 보면 거의 비슷한데 저런형태로도 표현할수 있다.

예제2는 Expression-bodied members 라고 하는데 아래 페이지를 한번 읽어보자.

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/expression-bodied-members#read-only-properties

 

Expression-bodied members - C# Programming Guide

Learn about expression-bodied members. See code examples that use expression body definition for properties, constructors, finalizers, and more.

docs.microsoft.com

쉽게 생각하면 코드를 한글자라도 줄인거라고 생각하면 되겠다.

 

그리고 <속성예제3> 을 보면 맴버필드 없이 속성만 구현해놨다.

저렇게 사용하면 자기자신이 맴버필드이자 속성이라고 생각하면된다.

즉 위 속성 1,2 예제들의 맴버필드와 속성이 합쳐진 것이라고 보면 된다.

예제3도 코드를 더 줄여놓은거라고 생각하면 된다.

자세한내용은 아래페이지를 참조하자

https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/classes-and-structs/properties

 

속성 - C# 프로그래밍 가이드

C#의 속성은 접근자 메서드를 사용하여 공용 데이터 멤버인 것처럼 private 필드의 값을 읽고, 쓰고, 계산하는 멤버입니다.

docs.microsoft.com

 

참고로 전체적으로 속성을 public 변수로 변경하는 추세다.

그래도 어떤형태로 사용하고 어떻게 쓰는지 알아야 과거에 만들어진 코드들을 읽을수 있고 분석할수 있기때문에 꼭 알아두자.

 

***숙제 :  속성을 사용하여 그림3과 같은 내가 입력한 문자가 아래 라벨에 바로 표시되는 예제를 만들어보자. 쓰레드는 사용하지말것.

댓글