속성 사용(C# 프로그래밍 가이드)

속성은 필드 및 메서드 모두의 측면을 결합합니다. 개체의 사용자에게 속성은 필드로 표시되며, 속성에 액세스하려면 동일한 구문이 필요합니다. 클래스의 구현자에게 속성은 get 접근자 및/또는 set 접근자를 나타내는 하나 또는 두 개의 코드 블록입니다. get 접근자에 대한 코드 블록은 속성을 읽을 때 실행되고, set 접근자에 대한 코드 블록은 속성에 새 값을 할당할 때 실행됩니다. set 접근자가 없는 속성은 읽기 전용으로 간주됩니다. get 접근자가 없는 속성은 쓰기 전용으로 간주됩니다. 두 접근자가 모두 있는 속성은 읽기/쓰기입니다.

필드와 달리 속성은 변수로 분류되지 않습니다. 따라서 ref 또는 out 매개 변수로 속성을 전달할 수 없습니다.

속성은 여러 가지 용도로 사용됩니다. 변경을 허용하기 전에 데이터의 유효성을 검사하고, 데이터가 실제로 데이터베이스 등의 다른 소스에서 검색되는 클래스에 데이터를 투명하게 공개하고, 데이터 변경 시 이벤트 발생, 다른 필드의 값 변경 등의 작업을 수행할 수 있습니다.

속성은 필드의 액세스 수준, 속성 형식, 속성 이름, get 접근자 및/또는 set 접근자를 선언하는 코드 블록을 차례로 지정하여 클래스 블록에서 선언됩니다. 예:

public class Date
{
    private int month = 7;  // Backing store

    public int Month
    {
        get
        {
            return month;
        }
        set
        {
            if ((value > 0) && (value < 13))
            {
                month = value;
            }
        }
    }
}

이 예제에서 Month는 속성으로 선언되었으므로, set 접근자를 통해 Month 값이 1에서 12 사이로 설정되도록 할 수 있습니다. Month 속성은 전용 필드를 사용하여 실제 값을 추적합니다. 속성 데이터의 실제 위치를 속성의 “백업 저장소”라고도 합니다. 일반적으로 속성은 전용 필드를 백업 저장소로 사용합니다. 속성 호출을 통해서만 필드를 변경할 수 있도록 하기 위해 필드는 private로 표시되었습니다. 공용 및 개인 액세스 제한에 대한 자세한 내용은 액세스 한정자를 참조하세요.

자동 구현 속성은 간단한 속성 선언을 위해 간소화된 구문을 제공합니다. 자세한 내용은 자동으로 구현된 속성을 참조하세요.

get 접근자

get 접근자 본문은 메서드 본문과 유사합니다. 속성 형식의 값을 반환해야 합니다. get 접근자의 실행은 필드 값을 읽는 것과 같습니다. 예를 들어 get 접근자에서 private 변수를 반환하고 최적화가 사용되는 경우 get 접근자 메서드 호출이 컴파일러에서 인라인되므로 메서드 호출 오버헤드가 없습니다. 그러나 가상 get 접근자 메서드는 컴파일러에서 런타임 시 실제로 호출될 수 있는 메서드를 컴파일 시간에 알 수 없기 때문에 인라인할 수 없습니다. 다음은 전용 필드 name의 값을 반환하는 get 접근자입니다.

class Person
{
    private string name;  // the name field
    public string Name    // the Name property
    {
        get
        {
            return name;
        }
    }
}

할당 대상을 제외하고 속성을 참조하는 경우 속성 값을 읽기 위해 get 접근자가 호출됩니다. 예:

Person person = new Person();
//...

System.Console.Write(person.Name);  // the get accessor is invoked here

get 접근자는 return 또는 throw 문으로 끝나야 하며, 제어가 접근자 본문을 벗어날 수 없습니다.

get 접근자를 사용하여 개체의 상태를 변경하는 것은 잘못된 프로그래밍 스타일입니다. 예를 들어 다음 접근자는 number 필드에 액세스할 때마다 개체의 상태가 변경되는 부작용을 생성합니다.

private int number;
public int Number
{
    get
    {
        return number++;   // Don't do this
    }
}

get 접근자를 사용하여 필드 값을 반환하거나 계산한 후 반환할 수 있습니다. 예:

class Employee
{
    private string name;
    public string Name
    {
        get
        {
            return name != null ? name : "NA";
        }
    }
}

앞의 코드 세그먼트에서 Name 속성에 값을 할당하지 않으면 NA 값이 반환됩니다.

set 접근자

set 접근자는 반환 형식이 void인 메서드와 비슷합니다. 형식이 속성의 형식인 value라는 암시적 매개 변수를 사용합니다. 다음 예제에서는 set 접근자가 Name 속성에 추가됩니다.

class Person
{
    private string name;  // the name field
    public string Name    // the Name property
    {
        get
        {
            return name;
        }
        set
        {
            name = value;
        }
    }
}

속성에 값을 할당하는 경우 새 값을 제공하는 인수를 사용하여 set 접근자가 호출됩니다. 예:

Person person = new Person();
person.Name = "Joe";  // the set accessor is invoked here                

System.Console.Write(person.Name);  // the get accessor is invoked here

set 접근자의 지역 변수 선언에 대해 암시적 매개 변수 이름 value를 사용하면 오류가 발생합니다.

설명

속성은 public, private, protected, internal 또는 protected internal로 표시될 수 있습니다. 이러한 액세스 한정자는 클래스 사용자가 속성에 액세스하는 방법을 정의합니다. 동일한 속성에 대한 getset 접근자가 서로 다른 액세스 한정자를 가질 수 있습니다. 예를 들어 get은 형식 외부에서 읽기 전용 액세스를 허용하도록 public이 되고, setprivate 또는 protected가 될 수 있습니다. 자세한 내용은 액세스 한정자를 참조하세요.

static 키워드를 사용하여 속성을 정적 속성으로 선언할 수 있습니다. 그러면 클래스의 인스턴스가 없는 경우에도 언제든지 호출자가 속성을 사용할 수 있습니다. 자세한 내용은 정적 클래스 및 정적 클래스 멤버를 참조하세요.

virtual 키워드를 사용하여 속성을 가상 속성으로 표시할 수 있습니다. 그러면 파생 클래스에서 override 키워드를 사용하여 속성 동작을 재정의할 수 있습니다. 이러한 옵션에 대한 자세한 내용은 상속을 참조하세요.

가상 속성을 재정의하는 속성이 sealed일 수도 있으며, 파생 클래스에 대해 더 이상 가상이 아니도록 지정합니다. 마지막으로, 속성을 abstract로 선언할 수 있습니다. 즉, 클래스에 구현이 없으며 파생 클래스가 자체 구현을 작성해야 합니다. 이러한 옵션에 대한 자세한 내용은 추상 및 봉인 클래스와 클래스 멤버를 참조하세요.

참고

static 속성의 접근자에 virtual, abstract 또는 override 한정자를 사용하면 오류가 발생합니다.

예제

이 예제에서는 인스턴스, 정적 및 읽기 전용 속성을 보여 줍니다. 키보드에서 직원 이름을 받고 NumberOfEmployees를 1만큼 증가한 다음 직원 이름과 번호를 표시합니다.

public class Employee
{
    public static int NumberOfEmployees;
    private static int counter;
    private string name;

    // A read-write instance property:
    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    // A read-only static property:
    public static int Counter
    {
        get { return counter; }
    }

    // A Constructor:
    public Employee()
    {
        // Calculate the employee's number:
        counter = ++counter + NumberOfEmployees;
    }
}

class TestEmployee
{
    static void Main()
    {
        Employee.NumberOfEmployees = 107;
        Employee e1 = new Employee();
        e1.Name = "Claude Vige";

        System.Console.WriteLine("Employee number: {0}", Employee.Counter);
        System.Console.WriteLine("Employee name: {0}", e1.Name);
    }
}
/* Output:
    Employee number: 108
    Employee name: Claude Vige
*/

예제

이 예제에서는 파생 클래스에서 이름이 같은 다른 속성에 의해 숨겨진 기본 클래스의 속성에 액세스하는 방법을 보여 줍니다.

public class Employee
{
    private string name;
    public string Name
    {
        get { return name; }
        set { name = value; }
    }
}

public class Manager : Employee
{
    private string name;

    // Notice the use of the new modifier:
    public new string Name
    {
        get { return name; }
        set { name = value + ", Manager"; }
    }
}

class TestHiding
{
    static void Main()
    {
        Manager m1 = new Manager();

        // Derived class property.
        m1.Name = "John";

        // Base class property.
        ((Employee)m1).Name = "Mary";

        System.Console.WriteLine("Name in the derived class is: {0}", m1.Name);
        System.Console.WriteLine("Name in the base class is: {0}", ((Employee)m1).Name);
    }
}
/* Output:
    Name in the derived class is: John, Manager
    Name in the base class is: Mary
*/

다음은 앞의 예제에서 중요한 사항입니다.

  • 파생 클래스의 Name 속성은 기본 클래스의 Name 속성을 숨깁니다. 이러한 경우 new 한정자는 파생 클래스의 속성 선언에 사용됩니다.

    public new string Name
    
  • (Employee) 캐스트는 기본 클래스의 숨겨진 속성에 액세스하는 데 사용됩니다.

    ((Employee)m1).Name = "Mary";
    

    멤버를 숨기는 방법에 대한 자세한 내용은 new 한정자를 참조하세요.

예제

이 예제에서 두 클래스 CubeSquare는 추상 클래스 Shape를 구현하고 해당 abstract Area 속성을 재정의합니다. 속성의 override 한정자를 사용합니다. 프로그램은 변을 입력으로 사용하고 사각형과 정육면체의 면적을 계산합니다. 또한 면적을 입력으로 사용하고 사각형 및 정육면체의 해당 변을 계산합니다.

abstract class Shape
{
    public abstract double Area
    {
        get;
        set;
    }
}

class Square : Shape
{
    public double side;

    public Square(double s)  //constructor
    {
        side = s;
    }

    public override double Area
    {
        get
        {
            return side * side;
        }
        set
        {
            side = System.Math.Sqrt(value);
        }
    }
}

class Cube : Shape
{
    public double side;

    public Cube(double s)
    {
        side = s;
    }

    public override double Area
    {
        get
        {
            return 6 * side * side;
        }
        set
        {
            side = System.Math.Sqrt(value / 6);
        }
    }
}

class TestShapes
{
    static void Main()
    {
        // Input the side:
        System.Console.Write("Enter the side: ");
        double side = double.Parse(System.Console.ReadLine());

        // Compute the areas:
        Square s = new Square(side);
        Cube c = new Cube(side);

        // Display the results:
        System.Console.WriteLine("Area of the square = {0:F2}", s.Area);
        System.Console.WriteLine("Area of the cube = {0:F2}", c.Area);
        System.Console.WriteLine();

        // Input the area:
        System.Console.Write("Enter the area: ");
        double area = double.Parse(System.Console.ReadLine());

        // Compute the sides:
        s.Area = area;
        c.Area = area;

        // Display the results:
        System.Console.WriteLine("Side of the square = {0:F2}", s.side);
        System.Console.WriteLine("Side of the cube = {0:F2}", c.side);
    }
}
/* Example Output:
    Enter the side: 4
    Area of the square = 16.00
    Area of the cube = 96.00

    Enter the area: 24
    Side of the square = 4.90
    Side of the cube = 2.00
*/

참고 항목

C# 프로그래밍 가이드
속성
인터페이스 속성
자동으로 구현된 속성