C #에서 개인 속성을 사용해야하는 이유가 있습니까?


246

방금 C # 속성 구문개인 액세스 수정 자 와 함께 사용할 수 있음을 깨달았습니다 .

private string Password { get; set; }

이것은 기술적으로 흥미롭지 만 개인 필드 에는 식이 훨씬 적기 때문에 언제 사용할 것인지 상상할 수 없습니다 .

private string _password;

그리고 내부적으로 얻을 수는 있지만 설정 하거나 설정할 없지만 개인 필드를 얻을 수없는 경우를 상상할 수 없습니다 .

private string Password { get; }

또는

private string Password { set; }

그러나 중첩 된 / 상속 된 클래스 의 유스 케이스가 있거나 get / set 에 속성 값을 반환하는 대신 논리 가 포함될 수 있습니다 . 속성을 단순하게 유지하고 명시 적 메소드가 논리를 수행하도록하는 경향이 있지만, 예 GetEncodedPassword().

어떤 이유로 든 C #에서 개인 속성을 사용합니까 아니면 기술적으로 가능하지만 실제로 사용되지 않는 실제 코드 구성 중 하나입니까?

추가

좋은 답변, 그들을 통해 나는 개인 재산에 대한 이러한 사용을 컬링 :

  • 개인 필드를 느리게로드해야하는 경우
  • 개인 필드에 추가 논리가 필요하거나 계산 된 값인 경우
  • 개인 필드는 디버그하기 어려울 수 있기 때문에
  • "자신에게 계약을 제시"
  • 직렬화의 일부로 노출 된 속성을 내부적으로 변환 / 단순화
  • 클래스 내에서 사용될 전역 변수 랩핑

개인 재산에 의해 권장되는 기술은 자체 캡슐화입니다 -참조 : sourcemaking.com/refactoring/self-encapsulate-field
LBushkin

답변:


212

값을 캐시해야하고 지연로드하려는 경우이를 사용합니다.

private string _password;
private string Password
{
    get
    {
        if (_password == null)
        {
            _password = CallExpensiveOperation();
        }

        return _password;
    }
}

42
이것에 대한 일반적인 패턴은 다음과 같습니다return _password ?? (_password = CallExpensiveOperation());
Marc

1
@EvAlex Lazy <T>를 사용하는 것이 좋습니다. 그러나 정적 항목 만 사용할 수 있으므로 (정적이 아닌) 메소드 또는 다른 멤버에 액세스 할 수 없습니다. 그건 그렇고 return _password ?? (_password = CallExpensiveOperation());한동안 나는 한 줄 문법을 선호합니다 . 또는 실제로 Resharper가 선호합니다 :).
Bart

4
C # 6 이후 @Marc는 get과 return을 작성할 필요조차 없습니다. private string Password => _password ?? (_password = CallExpensiveOperation());
Otto Abnormalverbraucher

1
C # 8을 사용하면 훨씬 짧습니다.private string Password => _password ??= CallExpensiveOperation();
Dave M

2
@Bas CallExpensiveOperation();포함 객체의 생성 / 초기화 중에 호출되며 속성에 처음 액세스 할 때 호출 되지 않기 때문에 지연 로딩이 아닙니다 .
Stefan Podskubka

142

내 코드에서 이것의 주요 사용법은 다른 사람들이 언급했듯이 지연 초기화입니다.

필드에 대한 개인 속성의 또 다른 이유는 개인 속성이 개인 필드보다 디버그하기가 훨씬 훨씬 쉽다는 것입니다. "이 필드는 예기치 않게 설정됩니다.이 필드를 설정 한 첫 번째 발신자는 누구입니까?"와 같은 것을 자주 알고 싶습니다. 세터에 중단 점을 놓고 이동하면 더 쉽습니다. 거기에 로깅을 넣을 수 있습니다. 거기에 성능 지표를 넣을 수 있습니다. 디버그 빌드에서 실행되는 일관성 검사를 수행 할 수 있습니다.

기본적으로 코드는 데이터보다 훨씬 강력합니다. . 필요한 코드를 작성할 수있는 모든 기술이 좋습니다. 필드를 사용하면 코드를 작성할 수 없으며 속성도 마찬가지입니다.


5
"코드가 데이터보다 훨씬 강력하다"고 말하는가? 인터넷 검색은 사용자를 가리키는 참조를 반환합니다. 내가 필요할 때 올바르게 인용 할 수 있도록 알고 싶습니다.
Joan Venge

24
@Joan : 몰라요. 내가 그것을 만들었거나 다른 누군가가 그 말을 듣고 "와우, 나는 그것을 완전히 훔쳐서 내가 그것을 훔친 사람에 관한 모든 것을 잊어야한다"고 생각했다.
Eric Lippert

1
+ CodeLens는 속성이 참조 된 위치를 알려줍니다
UuDdLrLrSs

43

아마도 중첩 / 상속 된 클래스의 유스 케이스가 있거나 get / set에 속성 값을 반환하는 대신 논리가 포함될 수 있습니다

속성의 getter 또는 setter에 대한 논리가 필요하지 않은 경우에도 개인적으로 사용합니다. 속성, 심지어 개인 속성을 사용하면 코드를 미래에 대비하여 나중에 필요한 경우 나중에 게터에 로직을 추가 할 수 있습니다.

속성에 결국 추가 논리가 필요할 수 있다고 생각되면 필드를 사용하는 대신 개인 속성으로 래핑하기 때문에 나중에 코드를 변경할 필요가 없습니다.


반 관련 사례 (귀하의 질문과는 다르지만), 나는 공공 재산에 개인 세터를 매우 자주 사용합니다.

public string Password 
{
    get; 
    private set;
}

이것은 공개 게터를 제공하지만 세터를 비공개로 유지합니다.


+1이 의미가 있습니다. "속성에 추가 논리가 필요할 수 있다고 생각되면 필드를 사용하는 대신 개인 속성으로 래핑하기도하므로 나중에 코드를 변경할 필요가 없습니다."
Edward Tanguay

7
개인 세터 <3
Earlz

20

개인용 get 전용 속성의 좋은 사용법은 계산 된 값입니다. 여러 번 개인 전용 읽기 전용 속성이 있었고 내 유형의 다른 필드에 대해 계산을 수행했습니다. 그것은 메서드에 가치가 없으며 다른 클래스에는 흥미가 없으므로 개인 재산입니다.


20

게으른 초기화는 예를 들어 깔끔한 곳입니다.

private Lazy<MyType> mytype = new Lazy<MyType>(/* expensive factory function */);

private MyType MyType { get { return this.mytype.Value; } }

// In C#6, you replace the last line with: private MyType MyType => myType.Value;

그런 다음 한 곳에서 게으르게 인스턴스화된다는 사실을 캡슐화 this.MyType하지 않고 어디에서나 쓸 수 있습니다 this.mytype.Value.

부끄러운 점 중 하나는 C #이 지원 필드를 속성으로 범위 지정 (즉, 속성 정의 내에 선언)하여 필드를 완전히 숨기고 속성을 통해서만 액세스 할 수 있도록하는 것입니다.


2
거기에 범위를 정하는 것이 합의되었다.
Chris Marisic

5
나는이 동일한 기술을 자주 사용하며 필드가 코드 본문으로 범위를 지정할 수 있기를 바랍니다. 좋은 기능이지만 우선 순위가 낮습니다.
Eric Lippert

5
@Eric Lippert- field-declarations 범위 accessor-declarations내 C # 위시리스트에서 오랫동안 1 위를 차지했습니다. 만약 당신이 그것을 (실제) 미래 버전으로 디자인하고 구현할 수 있다면, 나는 당신에게 케이크를 구울 것입니다.
Jeffrey L Whitledge

13

내가 생각할 수있는 유일한 사용법

private bool IsPasswordSet 
{ 
     get
     {
       return !String.IsNullOrEmpty(_password);
     }
}

다른 개인 변수에서 계산되는 유용한 클래스의 속성에 +1
Daren Thomas

2
비공개 방법을 사용하지 않는 이유private bool IsPasswordSet() { return !String.IsNullOrEmpty(_password); }
Roman

10

속성과 필드는 일대일이 아닙니다. 속성은 클래스의 인터페이스 (공개 또는 내부 인터페이스에 대해 이야기하든)에 관한 것이며 필드는 클래스의 구현에 관한 것입니다. 속성은 필드를 노출하는 방법으로 만 보여서는 안되며 클래스의 의도와 목적을 노출하는 방법으로 보여야합니다.

클래스를 구성하는 것에 대해 소비자에게 계약을 제시하기 위해 속성을 사용하는 것과 마찬가지로 매우 유사한 이유로 계약을 제시 할 수도 있습니다. 예, 개인 속성이 의미가있을 때 사용합니다. 때로는 사유 재산이 게으른 로딩과 같은 구현 세부 사항을 숨길 수 있습니다. 속성이 실제로 여러 필드와 측면의 대기업이거나 속성이 각 호출마다 가상으로 인스턴스화되어야한다는 사실입니다 (think DateTime.Now). 수업의 백엔드에서도 스스로를 시행하는 것이 합리적 인 경우가 있습니다.


+1 : "매우 비슷한 이유로 계약을 제시 할 수 있습니다"
Edward Tanguay

8

나는 DataContractSerializer이 사용법을 지원하는 protobuf-net 과 같은 것들과 함께 직렬화에 사용합니다 XmlSerializer. 직렬화의 일부로 객체를 단순화해야하는 경우에 유용합니다.

public SomeComplexType SomeProp { get;set;}
[DataMember(Order=1)]
private int SomePropProxy {
    get { return SomeProp.ToInt32(); }
    set { SomeProp = SomeComplexType.FromInt32(value); }
}

6

내가 항상하는 한 가지는 "전역"변수 / 캐시를 저장하는 것입니다 HttpContext.Current

private static string SomeValue{
  get{
    if(HttpContext.Current.Items["MyClass:SomeValue"]==null){
      HttpContext.Current.Items["MyClass:SomeValue"]="";
    }
    return HttpContext.Current.Items["MyClass:SomeValue"];
  }
  set{
    HttpContext.Current.Items["MyClass:SomeValue"]=value;
  }
}

5

나는 때때로 그들을 사용합니다. 속성에 중단 점을 쉽게 넣거나 로깅 문 등을 추가 할 수 있으면 디버깅이 쉬워집니다.

나중에 어떤 방식으로 데이터 유형을 변경해야하거나 리플렉션을 사용해야하는 경우에도 유용 할 수 있습니다.


같게; get / set과 관련된 논리가있는 경우 개인 또는 보호 된 속성을 사용하는 경우가 있습니다. 그것은 일반적으로 얼마나 많은 논리에 달려 있습니다 : 속성에서 할 간단한 논리, 일반적으로 보조 함수를 사용하는 많은 논리. 코드를 가장 유지 관리하기 쉽게 만드는 것.
TechNeilogy

5

개인 속성을 사용하여 자주 사용하는 하위 속성에 액세스하기위한 코드를 줄입니다.

    private double MonitorResolution
    {
        get { return this.Computer.Accesories.Monitor.Settings.Resolution; }
    }

하위 속성이 많은 경우에 유용합니다.


2

get / set 메소드 (비공개 메소드 포함)로 멤버 만 수정하는 것이 일반적입니다. 이제 그 뒤에있는 논리는 get / set이 항상 특정 방식 (예 : 이벤트 발생)으로 동작한다는 것을 알기 때문에 속성 체계에 포함되지 않기 때문에 의미가 없습니다 ... 그러나 오래된 습관은 열심히 죽습니다.


2

속성 세트 또는 가져 오기와 관련된 논리가 있고 (게으른 초기화 생각) 속성이 클래스의 몇 곳에서 사용될 때 완벽하게 이해됩니다.

그냥 역행 필드라면? 좋은 이유는 없습니다.


2

나는이 질문이 매우 오래되었다는 것을 알고 있지만 아래 정보는 현재 답변에 없었습니다.

내부적으로 얻을 수는 있지만 설정할 수없는 상황을 상상할 수 없습니다

의존성을 주입하는 경우 읽기 전용 속성을 나타내는 setter가 아닌 속성에 Getter가 있어야 할 수 있습니다. 즉, 속성은 생성자에서만 설정할 수 있으며 클래스 내의 다른 코드로 변경할 수 없습니다.

또한 Visual Studio Professional은 필드가 아닌 속성에 대한 정보를 제공하므로 필드가 사용중인 항목을보다 쉽게 ​​확인할 수 있습니다.

PorpField


1

글쎄, 언급 한 사람이 없으므로 데이터를 확인하거나 변수를 잠그는 데 사용할 수 있습니다.

  • 확인

    string _password;
    string Password
    {
        get { return _password; }
        set
        {
            // Validation logic.
            if (value.Length < 8)
            {
                throw new Exception("Password too short!");
            }
    
            _password = value;
        }
    }
  • 잠금

    object _lock = new object();
    object _lockedReference;
    object LockedReference
    { 
        get
        {
            lock (_lock)
            {
                return _lockedReference;
            }
        }
        set
        {
            lock (_lock)
            {
                _lockedReference = value;
            }
        }
    }

    참고 : 참조를 잠글 때 참조 된 개체의 멤버에 대한 액세스는 잠그지 않습니다.

게으른 참조 : 게으른로드 할 때 요즘 AsyncLazy 가있는 비동기를 수행해야 할 수도 있습니다 . Visual Studio SDK 2015 이전 버전이거나 사용하지 않는 경우 AsyncEx의 AsyncLazy를 사용할 수도 있습니다 .


0

명시 적 필드의 좀 더 이국적인 용도는 다음과 같습니다.

  • 당신 은 값 을 사용 ref하거나 사용해야 out합니다-아마도 Interlocked카운터 이기 때문에
  • 이되는 구성 A의 예를 들어 기본 레이아웃을 표현하기 위해 struct명시 적 레이아웃 (아마도 ++는 C에 매핑 덤프, 또는하기unsafe 코드)
  • 역사적으로 유형은 BinaryFormatter자동 필드 처리 와 함께 사용되었습니다 (자동 소품으로 변경하면 이름이 변경되어 직렬 변환기가 손상됨)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.