다음을 통해 공유


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

속성은 데이터 필드의 값을 읽거나 쓰거나 계산하는 유연한 메커니즘을 제공하는 멤버입니다. 속성은 공용 데이터 멤버로 표시되지만, 접근자라는 특수 메서드로 구현됩니다. 이 기능을 통해 호출자는 데이터에 쉽게 액세스할 수 있으며 데이터 안전성과 유연성 수준을 올리는 데에도 도움이 됩니다. 속성 구문은 필드에 대한 자연 확장입니다. 필드는 스토리지 위치를 정의합니다.

public class Person
{
    public string? FirstName;

    // Omitted for brevity.
}

자동으로 구현된 속성

속성 정의에는 해당 속성의 값을 검색하고 할당하는 getset 접근자에 대한 선언이 포함됩니다.

public class Person
{
    public string? FirstName { get; set; }

    // Omitted for brevity.
}

앞의 예제에서는 자동으로 구현된 속성을 보여줍니다. 컴파일러는 속성에 대한 숨겨진 지원 필드를 생성합니다. 또한 컴파일러는 getset 접근자의 본문을 구현합니다. 모든 특성은 자동으로 구현된 속성에 적용됩니다. 특성에 field: 태그를 지정하여 컴파일러 생성 지원 필드에 특성을 적용할 수 있습니다.

속성에 대한 닫는 중괄호 뒤의 값을 설정하여 기본값이 아닌 값으로 속성을 초기화할 수 있습니다. FirstName 속성의 초기 값을 null 대신 빈 문자열로 설정할 수도 있습니다. 다음 코드와 같이 지정할 수 있습니다.

public class Person
{
    public string FirstName { get; set; } = string.Empty;

    // Omitted for brevity.
}

필드 백업 속성

C# 13에서는 키워드 미리 보기 기능을 사용하여 속성에 대한 접근자에서 유효성 검사 또는 기타 논리를 field 추가할 수 있습니다. 키워드는 field 속성에 대한 컴파일러 합성 지원 필드에 액세스합니다. 이를 통해 별도의 지원 필드를 명시적으로 선언하지 않고 속성 접근자를 작성할 수 있습니다.

public class Person
{
    public string? FirstName 
    { 
        get;
        set => field = value.Trim(); 
    }

    // Omitted for brevity.
}

Important

field 키워드는 C# 13의 미리 보기 기능입니다. 상황별 키워드를 사용하려면 .NET 9를 preview 사용하고 field 프로젝트 파일에서 요소를 설정 <LangVersion> 해야 합니다.

이름이 지정된 field필드가 field 있는 클래스에서 키워드 기능을 사용하는 데 주의해야 합니다. 새 field 키워드는 속성 접근자의 범위에 명명된 field 필드를 숨깁니다. 변수의 field 이름을 변경하거나 토큰을 사용하여 @ 식별자를 .로 @field참조 field 할 수 있습니다. 키워드에 대한 field 기능 사양을 읽어 자세히 알아볼 수 있습니다.

필수 속성

앞의 예제에서는 호출자가 FirstName 속성을 설정하지 않고 기본 생성자를 사용하여 Person을 만들 수 있습니다. 속성이 형식을 nullable 문자열로 변경했습니다. C# 11부터 호출자가 속성을 설정하도록 요청할 수 있습니다.

public class Person
{
    public Person() { }

    [SetsRequiredMembers]
    public Person(string firstName) => FirstName = firstName;

    public required string FirstName { get; init; }

    // Omitted for brevity.
}

앞의 코드는 Person 클래스에서 두 가지를 변경합니다. 먼저, FirstName 속성 선언에는 required 한정자가 포함되어 있습니다. 즉, 새로운 Person을 만드는 코드 모든 코드는 개체 이니셜라이저를 사용하여 이 속성을 설정해야 합니다. 둘째, firstName 매개 변수를 사용하는 생성자에는 System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute 특성이 있습니다. 이 특성은 이 생성자가 모든required 멤버를 설정한다는 것을 컴파일러에 알립니다. 이 생성자를 사용하는 호출자는 개체 이니셜라이저로 required 속성을 설정할 필요가 없습니다.

Important

requirednull을 허용하지 않음을 혼동하지 마세요. required 속성을 null 또는 default로 설정하는 것이 유효합니다. 이 예의 string과 같이 형식이 null을 허용하지 않는 경우 컴파일러는 경고를 발급합니다.

var aPerson = new Person("John");
aPerson = new Person{ FirstName = "John"};
// Error CS9035: Required member `Person.FirstName` must be set:
//aPerson2 = new Person();

식 본문 정의

속성 접근자는 한 줄 문으로 구성되는 경우가 많습니다. 접근자가 식의 결과를 할당하거나 반환합니다. 이러한 속성은 식 본문 멤버로 구현할 수 있습니다. 식 본문 정의는 => 토큰과 속성에 할당하거나 속성에서 검색할 식으로 구성됩니다.

읽기 전용 속성은 get 접근자를 식 본문 멤버로 구현할 수 있습니다. 다음 예제에서는 읽기 전용 Name 속성을 식 본문 멤버로 구현합니다.

public class Person
{
    public Person() { }

    [SetsRequiredMembers]
    public Person(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
    }

    public required string FirstName { get; init; }
    public required string LastName { get; init; }

    public string Name => $"{FirstName} {LastName}";

    // Omitted for brevity.
}

Name 속성은 계산된 속성입니다. Name에 대한 지원 필드가 없습니다. 속성은 매번 계산합니다.

Access Control

앞의 예제에서는 읽기/쓰기 속성을 살펴보았습니다. 읽기 전용 속성을 만들거나 set 및 get 접근자에 대해 다른 액세스 가능성을 제공할 수도 있습니다. 클래스에서 Person 속성 값을 클래스의 FirstName 다른 메서드에서만 변경할 수 있도록 설정해야 한다고 가정합니다. 다음 대신 set 접근자 private 접근성을 internal 제공할 수 있습니다 public.

public class Person
{
    public string? FirstName { get; private set; }

    // Omitted for brevity.
}

FirstName 속성을 모든 코드에서 읽을 수 있지만 Person 클래스의 코드에서만 할당할 수 있습니다.

set 또는 get 접근자에 제한적인 액세스 한정자를 추가할 수 있습니다. 개별 접근자에 대한 액세스 한정자는 속성의 액세스보다 더 제한적이어야 합니다. 위의 코드는 FirstName 속성이 public이지만 set 접근자가 private이므로 유효합니다. public 접근자를 사용하여 private 속성을 선언할 수 없습니다. 속성 선언을 protected, internal, protected internal 또는 private로 선언할 수도 있습니다.

set 접근자에 대해 두 가지 특수 액세스 한정자가 있습니다.

  • set 접근자는 액세스 한정자로 init을 사용할 수 있습니다. 해당 set 접근자는 개체 이니셜라이저 또는 형식의 생성자에서만 호출할 수 있습니다. set 접근자의 private보다 더 제한적입니다.
  • 자동으로 구현된 속성은 접근자 없이 접근자를 선언할 get set 수 있습니다. 이 경우 컴파일러는 형식의 생성자에서만 set 접근자를 호출할 수 있습니다. set 접근자의 init 접근자보다 더 제한적입니다.

다음과 같이 Person 클래스를 수정합니다.

public class Person
{
    public Person(string firstName) => FirstName = firstName;

    public string FirstName { get; }

    // Omitted for brevity.
}

앞의 예에서는 호출자가 FirstName 매개 변수를 포함하는 생성자를 사용해야 합니다. 호출자는 개체 이니셜라이저를 사용하여 속성에 값을 할당할 수 없습니다. 이니셜라이저를 지원하려면 다음 코드에 표시된 대로 set 접근자를 init 접근자로 만들 수 있습니다.

public class Person
{
    public Person() { }
    public Person(string firstName) => FirstName = firstName;

    public string? FirstName { get; init; }

    // Omitted for brevity.
}

이러한 한정자는 적절한 초기화를 강제로 적용하기 위해 required 한정자와 함께 사용되는 경우가 많습니다.

지원 필드가 있는 속성

계산된 속성의 개념과 프라이빗 필드를 혼합하고 캐시된 평가 속성을 만들 수 있습니다. 예를 들어 첫 번째 액세스에서 문자열 서식이 지정되도록 FullName 속성을 업데이트합니다.

public class Person
{
    public Person() { }

    [SetsRequiredMembers]
    public Person(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
    }

    public required string FirstName { get; init; }
    public required string LastName { get; init; }

    private string? _fullName;
    public string FullName
    {
        get
        {
            if (_fullName is null)
                _fullName = $"{FirstName} {LastName}";
            return _fullName;
        }
    }
}

FirstNameLastName 속성이 읽기 전용이므로 이 구현이 작동합니다. 사용자는 자신의 이름을 변경할 수 있습니다. set 접근자를 허용하도록 FirstNameLastName 속성을 업데이트하려면 fullName의 캐시된 값을 무효화해야 합니다. fullName 필드가 다시 평가되도록 FirstNameLastName 속성의 set 접근자를 수정합니다.

public class Person
{
    private string? _firstName;
    public string? FirstName
    {
        get => _firstName;
        set
        {
            _firstName = value;
            _fullName = null;
        }
    }

    private string? _lastName;
    public string? LastName
    {
        get => _lastName;
        set
        {
            _lastName = value;
            _fullName = null;
        }
    }

    private string? _fullName;
    public string FullName
    {
        get
        {
            if (_fullName is null)
                _fullName = $"{FirstName} {LastName}";
            return _fullName;
        }
    }
}

이 최종 버전은 필요한 경우에만 FullName 속성을 평가합니다. 유효한 경우 이전에 계산한 버전이 사용됩니다. 그렇지 않으면 계산이 캐시된 값을 업데이트합니다. 이 클래스를 사용하는 개발자는 구현 세부 정보를 알 필요가 없습니다. 이러한 내부 변경 내용은 Person 개체의 사용에 영향을 주지 않습니다.

C# 13부터 partial 클래스에서 partial 속성을 만들 수 있습니다. 속성에 대한 구현 선언은 partial 자동으로 구현된 속성이 될 수 없습니다. 자동으로 구현된 속성은 선언 부분 속성 선언과 동일한 구문을 사용합니다.

속성

속성은 클래스 또는 개체에 있는 스마트 필드의 한 형태입니다. 개체 외부에서는 개체의 필드와 유사하게 나타납니다. 그러나 C# 기능의 전체 팔레트를 사용하여 속성을 구현할 수 있습니다. 유효성 검사, 다른 액세스 가능성, 지연 평가 또는 시나리오에 필요한 모든 요구 사항을 제공할 수 있습니다.

  • 사용자 지정 접근자 코드가 필요하지 않은 단순 속성은 식 본문 정의 또는 자동으로 구현된 속성으로 구현할 수 있습니다.
  • 속성을 사용하면 클래스가 구현 또는 검증 코드를 숨기는 동시에 값을 가져오고 설정하는 방법을 공개적으로 노출할 수 있습니다.
  • get 속성 접근자는 속성 값을 반환하는 데 사용되고 set 속성 접근자는 새 값을 할당하는 데 사용됩니다. init 속성 접근자는 개체 생성 중에만 새 값을 할당하는 데 사용됩니다. 이러한 접근자는 각기 다른 액세스 수준을 가질 수 있습니다. 자세한 내용은 접근자 액세스 가능성 제한을 참조하세요.
  • 키워드는 set 또는 init 접근자가 할당하는 값을 정의하는 데 사용됩니다.
  • 속성은 읽기/쓰기(getset 접근자 모두 포함), 읽기 전용(get 접근자는 포함하지만 set 접근자는 포함 안 함) 또는 쓰기 전용(set 접근자는 포함하지만 get 접근자는 포함 안 함)일 수 있습니다. 쓰기 전용 속성은 거의 없습니다.

C# 언어 사양

자세한 내용은 C# 언어 사양속성을 참조하세요. 언어 사양은 C# 구문 및 사용법에 대 한 신뢰할 수 있는 소스 됩니다.

참고 항목