속성 사용(C# 프로그래밍 가이드)
속성은 필드 및 메서드 모두의 측면을 결합합니다. 개체의 사용자에게 속성은 필드로 표시되며, 속성에 액세스하려면 동일한 구문이 필요합니다. 클래스의 구현자에 속성은 get
접근자 및/또는 set
또는 init
접근자를 나타내는 하나 또는 두 개의 코드 블록입니다. get
접근자에 대한 코드 블록은 속성을 읽을 때 실행됩니다. 속성에 값이 할당되면 set
또는 init
접근자에 대한 코드 블록이 실행됩니다. set
접근자가 없는 속성은 읽기 전용으로 간주됩니다. get
접근자가 없는 속성은 쓰기 전용으로 간주됩니다. 두 접근자가 모두 있는 속성은 읽기/쓰기입니다. set
접근자 대신 init
접근자를 사용하여 속성을 개체 초기화의 일부로 설정할 수 있지만 그렇지 않으면 읽기 전용으로 설정할 수 있습니다.
필드와 달리 속성은 변수로 분류되지 않습니다. 따라서 속성을 ref
또는 out
매개 변수로 전달할 수 없습니다.
속성에는 다음과 같은 여러 가지 용도가 있습니다.
- 변경을 허용하기 전에 데이터의 유효성을 검사할 수 있습니다.
- 데이터베이스와 같은 다른 원본에서 해당 데이터가 검색되는 클래스에 데이터를 투명하게 노출할 수 있습니다.
- 이벤트를 발생하거나 다른 필드의 값을 변경하는 등 데이터가 변경될 때 작업을 수행할 수 있습니다.
속성은 필드의 액세스 수준, 속성 형식, 속성 이름, get
접근자 및/또는 set
접근자를 선언하는 코드 블록을 차례로 지정하여 클래스 블록에서 선언됩니다. 예시:
public class Date
{
private int _month = 7; // Backing store
public int Month
{
get => _month;
set
{
if ((value > 0) && (value < 13))
{
_month = value;
}
}
}
}
이 예제에서 Month
는 속성으로 선언되었으므로, set
접근자를 통해 Month
값이 1에서 12 사이로 설정되도록 할 수 있습니다. Month
속성은 전용 필드를 사용하여 실제 값을 추적합니다. 속성 데이터의 실제 위치를 속성의 “백업 저장소”라고도 합니다. 일반적으로 속성은 전용 필드를 백업 저장소로 사용합니다. 속성 호출을 통해서만 필드를 변경할 수 있도록 하기 위해 필드는 private로 표시되었습니다. 공용 및 개인 액세스 제한에 대한 자세한 내용은 액세스 한정자를 참조하세요. 자동으로 구현된 속성은 단순 속성 선언에 대한 간소화된 구문을 제공합니다. 자세한 내용은 자동으로 구현된 속성을 참조 하세요.
get 접근자
get
접근자 본문은 메서드 본문과 유사합니다. 속성 형식의 값을 반환해야 합니다. C# 컴파일러 및 JIT(Just-In-Time) 컴파일러는 get
접근자를 구현하기 위한 일반적인 패턴을 검색하고 이러한 패턴을 최적화합니다. 예를 들어 계산을 수행하지 않고 필드를 반환하는 get
접근자가 해당 필드의 메모리 읽기에 최적화될 수 있습니다. 자동으로 mplemented 속성이 이 패턴을 따르고 이러한 최적화의 이점을 누릴 수 있습니다. 그러나 컴파일러가 실제로 런타임에 호출될 수 있는 메서드를 컴파일 시간에 알지 못하기 때문에 가상 get
접근자 메서드를 인라인화할 수 없습니다. 다음 예에서는 프라이빗 필드 _name
의 값을 반환하는 get
접근자를 보여 줍니다.
class Employee
{
private string _name; // the name field
public string Name => _name; // the Name property
}
할당 대상을 제외하고 속성을 참조하는 경우 속성 값을 읽기 위해 get
접근자가 호출됩니다. 예시:
var employee= new Employee();
//...
System.Console.Write(employee.Name); // the get accessor is invoked here
get
접근자는 return 또는 throw 문으로 끝나야 하며, 제어가 접근자 본문을 벗어날 수 없습니다.
Warning
get
접근자를 사용하여 개체의 상태를 변경하는 것은 잘못된 프로그래밍 스타일입니다.
get
접근자를 사용하여 필드 값을 반환하거나 계산한 후 반환할 수 있습니다. 예시:
class Manager
{
private string _name;
public string Name => _name != null ? _name : "NA";
}
이전 예제에서는 Name
속성에 값을 할당하지 않으면 NA
값을 반환합니다.
set 접근자
set
접근자는 반환 형식이 void인 메서드와 비슷합니다. 형식이 속성의 형식인 value
라는 암시적 매개 변수를 사용합니다. 컴파일러 및 JIT 컴파일러는 set
또는 init
접근자에 대한 일반적인 패턴도 인식합니다. 이러한 일반적인 패턴은 지원 필드에 대한 메모리를 직접 작성하여 최적화됩니다. 다음 예제에서는 set
접근자가 Name
속성에 추가됩니다.
class Student
{
private string _name; // the name field
public string Name // the Name property
{
get => _name;
set => _name = value;
}
}
속성에 값을 할당하는 경우 새 값을 제공하는 인수를 사용하여 set
접근자가 호출됩니다. 예시:
var student = new Student();
student.Name = "Joe"; // the set accessor is invoked here
System.Console.Write(student.Name); // the get accessor is invoked here
set
접근자의 지역 변수 선언에 대해 암시적 매개 변수 이름 value
를 사용하면 오류가 발생합니다.
Init 접근자
init
접근자를 만드는 코드는 set
대신 init
키워드를 사용한다는 점을 제외하면 set
접근자를 만드는 코드와 같습니다. 차이점은 init
접근자는 생성자 또는 object-initializer를 통해서만 사용할 수 있다는 것입니다.
설명
속성은 public
, private
, protected
, internal
, protected internal
또는 private protected
로 표시될 수 있습니다. 이러한 액세스 한정자는 클래스 사용자가 속성에 액세스하는 방법을 정의합니다. 동일한 속성에 대한 get
및 set
접근자는 다른 액세스 한정자를 가질 수 있습니다. 예를 들어 get
(이)가 public
(을)를 형식 외부에서 읽기 전용 액세스를 허용하도록 할 수 있으며 set
(은)는 private
또는 protected
일 수 있습니다. 자세한 내용은 액세스 한정자를 참조하세요.
static
키워드를 사용하여 속성을 정적 속성으로 선언할 수 있습니다. 클래스의 인스턴스가 없더라도 호출자는 언제든지 정적 속성을 사용할 수 있습니다. 자세한 내용은 static 클래스 및 static 클래스 멤버를 참조하세요.
가상 키워드를 사용하여 속성을 가상 속성으로 표시할 수 있습니다. 가상 속성을 사용하면 파생 클래스가 override 키워드를 사용하여 속성 동작을 재정의할 수 있습니다. 이러한 옵션에 대한 자세한 내용은 상속을 참조하세요.
가상 속성을 재정의하는 속성이 sealed일 수도 있으며, 파생 클래스에 대해 더 이상 가상이 아니도록 지정합니다. 마지막으로, 속성을 abstract로 선언할 수 있습니다. 추상 속성은 클래스의 구현을 정의하지 않으며 파생 클래스는 자체 구현을 작성해야 합니다. 이러한 옵션에 대한 자세한 내용은 추상 및 봉인 클래스와 클래스 멤버를 참조하세요.
예제
이 예제에서는 인스턴스, 정적 및 읽기 전용 속성을 보여 줍니다. 키보드에서 직원 이름을 받고 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 => _name;
set => _name = value;
}
// A read-only static property:
public static int Counter => _counter;
// A Constructor:
public Employee() => _counter = ++NumberOfEmployees; // Calculate the employee's number:
}
숨김 속성 예제
이 예제에서는 파생 클래스에서 이름이 같은 다른 속성에 의해 숨겨진 기본 클래스의 속성에 액세스하는 방법을 보여 줍니다.
public class Employee
{
private string _name;
public string Name
{
get => _name;
set => _name = value;
}
}
public class Manager : Employee
{
private string _name;
// Notice the use of the new modifier:
public new string Name
{
get => _name;
set => _name = value + ", Manager";
}
}
class TestHiding
{
public static void Test()
{
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 한정자를 참조하세요.
재정의 속성 예제
이 예제에서 두 클래스 Cube
및 Square
는 추상 클래스 Shape
를 구현하고 해당 abstract Area
속성을 재정의합니다. 속성의 override 한정자를 사용합니다. 프로그램은 변을 입력으로 사용하고 사각형과 정육면체의 면적을 계산합니다. 또한 면적을 입력으로 사용하고 사각형 및 정육면체의 해당 변을 계산합니다.
abstract class Shape
{
public abstract double Area
{
get;
set;
}
}
class Square : Shape
{
public double side;
//constructor
public Square(double s) => side = s;
public override double Area
{
get => side * side;
set => side = System.Math.Sqrt(value);
}
}
class Cube : Shape
{
public double side;
//constructor
public Cube(double s) => side = s;
public override double Area
{
get => 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
*/
참고 항목
.NET