.NET 속성-개인 집합 또는 읽기 전용 속성을 사용합니까?


45

어떤 상황에서 속성에 개인 집합을 사용해야하는 것과 ReadOnly 속성을 만들어야합니까? 아래의 두 가지 매우 단순한 예를 고려하십시오.

첫 번째 예 :

Public Class Person

    Private _name As String

    Public Property Name As String
        Get
            Return _name
        End Get
        Private Set(ByVal value As String)
            _name = value
        End Set
    End Property

    Public Sub WorkOnName()

        Dim txtInfo As TextInfo = _
            Threading.Thread.CurrentThread.CurrentCulture.TextInfo

        Me.Name = txtInfo.ToTitleCase(Me.Name)

    End Sub

End Class

// ----------

public class Person
{
    private string _name;
    public string Name
    {
        get { return _name; }
        private set { _name = value; }
    }

    public void WorkOnName()
    {
        TextInfo txtInfo = System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo;
        this.Name = txtInfo.ToTitleCase(this.Name);
    }
}

두 번째 예 :

Public Class AnotherPerson

    Private _name As String

    Public ReadOnly Property Name As String
        Get
            Return _name
        End Get
    End Property

    Public Sub WorkOnName()

        Dim txtInfo As TextInfo = _
            Threading.Thread.CurrentThread.CurrentCulture.TextInfo

        _name = txtInfo.ToTitleCase(_name)

    End Sub

End Class

// ---------------

public class AnotherPerson
{
    private string _name;
    public string Name
    {
        get { return _name; }
    }

    public void WorkOnName()
    {
        TextInfo txtInfo = System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo;
        _name = txtInfo.ToTitleCase(_name);
    }
}

둘 다 동일한 결과를 산출합니다. 이것이 옳고 그른 것이 아닌 상황이며, 단지 선호의 문제입니까?


public string Name { get; protected set; }상속을 통해.
samis

답변:


42

몇 가지 이유가 있습니다 private set.

1) 백업 필드를 전혀 사용하지 않고 읽기 전용 자동 속성을 원하는 경우 :

public string Name { get; private set; }   

public void WorkOnName()
{
    TextInfo txtInfo = Thread.CurrentThread.CurrentCulture.TextInfo;
    Name = txtInfo.ToTitleCase(Name);
}  

2) 클래스 내부에서 변수를 수정할 때 추가 작업을 수행하고 단일 위치에서 변수를 캡처하려는 경우 :

private string _name = string.Empty;
public string Name 
{ 
    get { return _name; }
    private set 
    {
        TextInfo txtInfo = Thread.CurrentThread.CurrentCulture.TextInfo;
        _name = txtInfo.ToTitleCase(value);
    }
}

그러나 일반적으로 개인적인 취향의 문제입니다. 내가 아는 한, 다른 것을 사용하는 성능상의 이유는 없습니다.


1
질문에 vb.net 태그가 있기 때문에 이것을 추가하기 만하지 만 vb.net에서는 get 또는 set에서 private을 사용하는 경우 후원자를 지정해야합니다. 따라서 vb.net에서는 속성을 읽기 전용으로 만드는 것이 실제로 덜 효과적이라고 생각합니다.
user643192

나는 그것에 대해 전혀 몰랐다 private set. :-)
Afzaal Ahmad Zeeshan

9
2016 년에이 답변을 읽는 사람들을위한 업데이트입니다. C # 6.0에는 읽기 전용 자동 속성이 도입되어 백업 필드없이 읽기 전용 속성을 가질 수 있습니다 public string Name { get; }. 변경 가능한 속성을 원하지 않는 경우 현재 선호되는 구문입니다.
Alexey

4
사용하지 않는 한 가지 좋은 이유 private set는 우리가 원하는 것처럼 변하지 않기 때문입니다. 진정한 불변 클래스를 구현하려면 읽기 전용이 필수입니다.
RubberDuck

읽기 전용을 사용하지 않는 성능상의 이유가있을 수 있습니다. 읽기 전용 구조체 필드의 메소드에 액세스 할 때 불필요한 구조체 복사가 발생하는 것으로 보입니다. codeblog.jonskeet.uk/2014/07/16/…
Triynko

28

외부에서 setter에 액세스 할 수없는 경우 개인 세트를 사용하십시오 .

사용하여 읽기 전용 당신이 할 때 한 번만 속성을 설정합니다 . 생성자 또는 변수 이니셜 라이저에서.

테스트 :

void Main()
{
    Configuration config = new Configuration();
    config.ResetConfiguration();

    ConfigurationReadOnly configRO = new ConfigurationReadOnly();
    configRO.ResetConfiguration();
}

public class Configuration
{
    public Color BackgroundColor { get; private set; }
    public Color ForegroundColor { get; private set; }
    public String Text { get; private set; }

    public Configuration()
    {
        BackgroundColor = Color.Black;
        ForegroundColor = Color.White;
        Text = String.Empty;
    }

    public void ResetConfiguration()
    {
        BackgroundColor = Color.Black;
        ForegroundColor = Color.White;
        Text = String.Empty;
    }
}

public class ConfigurationReadOnly
{
    public readonly Color BackgroundColor;
    public readonly Color ForegroundColor;
    public readonly String Text;

    public ConfigurationReadOnly()
    {
        BackgroundColor = Color.Black;
        ForegroundColor = Color.White;
        Text = String.Empty;
    }

    public void ResetConfiguration()
    {
        BackgroundColor = Color.Black; // compile error: due to readonly keyword
        ForegroundColor = Color.White; // compile error: due to readonly keyword
        Text = String.Empty; // compile error: due to readonly keyword
    }
}

나는 당신의 대답에 동의하지만, 당신의 모범은 약간의 개선을 사용할 수 있습니다. 컴파일러 오류가 발생하는 위치에 대한 설명을 원할 수 있습니다.
Michael Richardson

NB C # readonly키워드에 해당하는 VB.NET 구문 ReadOnly은 속성 대신 필드 에 적용 됩니다.
Zev Spitz

8

세 번째 옵션을 제안해도 될까요?

public class Person
{
    public string Name { get; protected set; }

    public void SetName(string name)
    {
        TextInfo txtInfo = System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo;
        this.Name = txtInfo.ToTitleCase(name);
    }
}

이렇게하면 Name 속성이 모든 외부 코드에 대해 읽기 전용으로 효과적으로 설정되고 명시적인 Set 메서드가 제공됩니다. 이름을 설정할 때 값을 변경하기 때문에 단순히 Name 속성 의 집합 을 사용하는 것보다 명시적인 Set을 선호합니다 . 일반적으로 속성 값 을 설정 하면 나중에 get 을 호출 할 때 동일한 값을 얻을 것으로 예상되는데 , set 에서 ToTitleCase를 수행 한 경우에는 발생하지 않습니다 .

그러나 당신이 말했듯이, 정답은 없습니다.


'private set'은 컴파일러에서 특별한 의미를 가지고 있다고 생각합니다 (개인 접근 자로 만 수행하는 것이 아니라). 보호 세트도 마찬가지입니까? 그렇지 않은 경우 개인 집합에 특수 의미가있는 경우 보호 집합과 의미가 어디에 있습니까? 이것을 설명하는 문서를 찾을 수 없었습니다.
Sprague

1
+1이지만 "SetName"대신 "Rename"메소드를 호출합니다.
MattDavey


4

두 번째 예를 사용하지 마십시오. getter 가져 오기 및 setter 설정을 넘어서 아무 일도 일어나지 않더라도 속성을 사용하는 요점은 해당 getter 및 setter를 통해 모든 액세스를 퍼널 링하여 나중에 동작을 변경해야하는 경우 한 곳.

두 번째 예는 속성을 설정하는 경우이를 포기합니다. 대규모의 복잡한 클래스에서이 접근 방식을 사용하고 나중에 속성의 동작을 변경해야하는 경우 개인 세터 인 한 곳에서 변경하는 대신 검색 및 교체 토지에있게됩니다.


2

세터의 액세스 수준을 변경해야 할 때마다 일반적으로 보호자 (이 클래스와 파생 클래스 만 값을 변경할 수 있음) 또는 친구 (내 어셈블리 멤버 만 값을 변경할 수 있음)로 변경했습니다.

그러나 개인 설정을 사용하면 백업 값을 변경하는 것 외에도 세터에서 다른 작업을 수행하려는 경우 완벽하게 이해됩니다. 앞서 지적한 바와 같이, 배킹 값을 직접 참조하지 않고 속성을 통해서만 액세스하는 것이 좋습니다. 이렇게하면 나중에 속성에 대한 변경 사항이 외부뿐만 아니라 내부적으로 적용됩니다. 그리고 속성 대 백킹 변수를 참조하면 성능이 저하되지 않습니다.


0

그리고 사실상 성능 저하가 없습니다 ...

그러나 명확히하기 위해 속성에 액세스하는 것이 지원 변수에 액세스하는 것보다 느립니다. 속성의 getter 및 setter는 Call 및 Return이 필요한 메서드이지만 속성의 지원 변수는 직접 액세스됩니다.

그렇기 때문에 코드 블록 내에서 속성의 getter에 여러 번 액세스 할 수있는 경우 속성 값이 먼저 캐시되고 (로컬 변수에 저장 됨) 대신 로컬 변수가 사용됩니다. 물론, 블록이 실행되는 동안 속성을 비동기 적으로 변경할 수 없다고 가정합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.