개인 세터 이해


93

C # 2로 시작된 개인 setter가 필요하다는 것을 이해하지 못합니다.

나를 위해 setter 메서드를 사용하면 사용자가 해당 클래스에서 일부 변수를 설정할 수 있습니다. 그렇게 할 때 변수를 사용자에게 직접 노출하지 않습니다. 대신에 우리는이 공용 setter 메서드를 통해이를 수행하도록합니다.

이것은 나를 위해 "캡슐화"를 사용하고 있습니다. private setter가 캡슐화를 적용 할 수 있다고 주장하는 몇 가지 주장이 있습니다.

공용 setter 메서드를 사용하여 캡슐화를 사용하지 않습니까? 개인 세터가 필요한 이유는 무엇입니까?

불변 클래스와 private setter가있는 클래스의 차이점은 무엇입니까?


1
나는 개인 세터를 아주 좋아했습니다. 추악한 수업을 리팩토링하는 데 도움이되었습니다. 또한 private File settingsFile = null;다음과 같이 상수가 아닌 인스턴스 변수를 한 번에 선언하고 설정할 수 없습니다. 다음 생성자 중 하나에서 : if (settingsFile == null) { settingsFile = GetSettingsFile() };. 그런 코드를 리팩토링하면 가끔 울었습니다. :). 생성자 앞에 멤버를 설정할 수 있다고해서 생성자가 여러 개인 경우 논리를 따르기가 어렵 기 때문에 그렇게해야한다는 의미는 아닙니다. private setter는 생성자 내부 또는 이후에 값을 설정하도록합니다.
Hamish Grubijan 2010 년

답변:


268

논리적으로.

private setter의 존재는 auto 속성을 사용할 수 있기 때문입니다.

public int MyProperty { get; set; }

읽기 전용으로 만들고 싶다면 어떻게 하시겠습니까?

public int MyProperty { get; }

젠장!! 내 수업에서 액세스 할 수 없습니다. 일반 속성처럼 만들어야합니다.

private int myProperty;
public int MyProperty { get { return myProperty; } }

흠 ...하지만 "자동 속성"기능이 없어졌습니다 ...

public int MyProperty { get; private set; }

AHHH .. 그게 낫다 !!


1
감사. 이것은 다시 의미가 있습니다
Dene

4
@ktutnik 당신이 한 방식으로 이것을 배치 해 주셔서 감사합니다. 나에게도 말이 돼요!
Vivek M. Chawla

4
잘 설명 된 답변.
imnk

3
Oh crap!! I can't access it from my own classC # 6.0부터 이것은 초기화 단계 밖에서 만 적용됩니다. 내 대답 참조 stackoverflow.com/a/34223746/198797
tsemer

1
#tsemer의 답변에 c # 6을 추가 {get; }하는 것은 { get; private set; }. 첫 번째 방법 property.GetSetMethod(true)은 반환 null하고 후자 는 반환합니다 true. 이것은 나를 놀라게했다.
emragins

37

private setter는 읽기 전용 속성이 있고 백업 변수를 명시 적으로 선언하지 않으려는 경우 유용합니다.

그래서:

public int MyProperty
{
    get; private set;
}

와 같다:

private int myProperty;
public int MyProperty
{
    get { return myProperty; }
}

자동 구현되지 않은 속성의 경우 클래스 에서 속성을 설정하는 일관된 방법을 제공 하므로 유효성 검사 등이 필요한 경우 한 곳만 사용할 수 있습니다.

최종 질문에 답하기 위해 MSDN은 개인 세터에 대해 다음과 같이 말합니다.

그러나 값 집합 (데이터) 만 캡슐화하고 동작이 거의 또는 전혀없는 작은 클래스 또는 구조체의 경우 set 접근자를 private으로 선언하여 개체를 변경 불가능하게 만드는 것이 좋습니다.

에서 자동 구현 속성에 대한 MSDN 페이지


1
개인 세터가 있기 때문에 여전히 부가 가치를 보지 못해 죄송합니다. setter를 노출하지 않으려면 getter 만 있습니다. 유효성 검사기를 추가하려면 공용 설정기를 사용하고 여기에 유효성 검사를 추가 할 수 있습니다. 액세스 할 수없는 세터가 필요한 이유는 무엇입니까? 내가 이해하는 방식은 "이 차를 타도 운전할 수 없습니다"와 같습니다. 내가 어차피 운전하지 않을 경우 왜 차를 주려고합니까
Dene

@Dene-틀리지 않았으므로 확실히 할 수 있습니다. 자동 구현 속성을 갖는 것은 필수가 아닙니다.
ChrisF

나는 내가 표현한 방식으로 행하는 것이 잘못된 것이 없다는 것을 압니다. C # 2의 즉흥적 인 작업에 감사하는 것뿐입니다. 주변에 과대 광고가 많이있는 것 같지만 느끼거나 가치를 볼 수 없습니다.
Dene

@Dene, 나는 그것에 대한 모든 과대 광고를 놓쳤다. 그러나 마침내 이것이 가능하다는 것을 알았을 때 .Net 1.1 시대의 긴 클래스를 정리하는 방법을 알았 기 때문에 기뻤습니다. 아직 설정되지 않은 속성의 값을 사용할 수 있지만 null로 설정된 인스턴스 멤버 변수의 값을 사용하는 것보다 덜 자연 스럽습니다.
Hamish Grubijan 2010 년

코드를 단순화합니다. 자동 속성과 같습니다. C #에 대한 많은 후속 업데이트는 코드를 더 간결하고 읽기 쉽게 만드는 것입니다. 그래도 원하는 경우 다른 방식으로 작업을 수행 할 수 있습니다. 이전 버전과의 호환성도 큰 목표 인 것 같습니다. 맛의 문제인 것 같아요.
niico

18

다소 간단합니다. Private setter를 사용하면 읽기 전용 공용 또는 보호 된 속성을 만들 수 있습니다.

그게 다야. 그게 유일한 이유입니다.

예, getter 만 지정하여 읽기 전용 속성을 만들 수 있지만 자동 구현 속성을 사용하면 get과 set을 모두 지정해야하므로 자동 구현 속성을 읽기 전용으로 지정하려면 다음을 사용해야 합니다. 개인 세터. 다른 방법은 없습니다.

Private setter가 자동 구현 된 읽기 전용 속성을 위해 특별히 생성되지는 않았지만, 그 사용은 주로 읽기 전용 속성과 리플렉션 및 직렬화 사용을 중심으로하는 다른 이유로 인해 좀 더 난해합니다.


2
감사합니다. "자동 구현 속성이 읽기 전용이되도록하려면 전용 setter를 사용해야합니다." 이것은 나에게 이해가된다
Dene

18

C # 6.0Auto-Property Initializers 구문 이 도입됨에 따라 인라인 또는 생성자 내에서 초기화시에만 설정되는 속성에 더 이상 전용 setter가 필요하지 않습니다.

이제 다음과 같은 새로운 구문이 컴파일됩니다.

인라인 초기화 속성

public class MyClass1 {
  public string MyProperty { get; } = "Aloha!"
}

생성자 초기화 속성

public class MyClass2 {
  public string MyProperty { get; }

  public MyClass2(string myProperty) {
    MyProperty = myProperty;
  }
}

3
@Ziggler, 실제로 그렇지 않습니다. OP도 요구하지 않습니다. 그는 그것들이 필요하다는 것을 이해하지 못합니다. 이 대답은 "이 시나리오에서는 더 이상 필요하지 않습니다."
tsemer

6

C # 2로 시작된 개인 setter가 필요하다는 것을 이해하지 못합니다.

예를 들어, 송장 클래스는 사용자가 Items 속성에서 항목을 추가하거나 제거 할 수 있도록 허용하지만 사용자가 Items 참조를 변경하는 것을 허용하지 않습니다 (즉, 사용자가 Items 속성을 다른 항목 목록 개체 인스턴스에 할당 할 수 없음).


public class Item
{
  public string item_code;
  public int qty;

  public Item(string i, int q)
  {
    this.item_code = i;
    this.qty = q;
  }
}

public class Invoice
{
  public List Items { get; private set; }

  public Invoice()
  {
    this.Items = new List();
  }
}

public class TestInvoice
{
  public void Test()
  {
    Invoice inv = new Invoice();
    inv.Items.Add(new Item("apple", 10));

    List my_items = new List();
    my_items.Add(new Item("apple", 10));

    inv.Items = my_items;   // compilation error here.
  }
}

+1은 속성이 private setter가 있더라도 public getter를 통해 조작 할 수 있음을 강조합니다.
user1725145

4

예를 들어 속성을 통해 실제 변수를 저장하지 않거나 값을 사용하여 무언가를 계산하지 않습니다.

이 경우 계산을 수행하는 방법을 만들 수 있습니다.

private void Calculate(int value)
{
 //...
}

또는 다음을 사용하여 수행 할 수 있습니다.

public int MyProperty {get; private set;}

이 경우 속성이 각 멤버 요소를 그대로 리팩토링하므로 나중에 사용하는 것이 좋습니다.

그 외에는 변수로 속성을 매핑한다고해도 말입니다. 이 경우 코드 내에서 다음과 같이 작성하고 싶습니다.

public int myprop;
public int MyProperty {get { return myprop;}}

... ...

this.myprop = 30;

... ...
if(this.MyProperty > 5)
   this.myprop = 40;

프로그래머가 Get에 MyProperty를 사용하고 Set에 대해 myprop를 사용하는 데 항상주의해야하기 때문에 위의 코드는 끔찍해 보입니다.

일관성을 위해 Rether는 Propoerty를 외부에서 읽기 전용으로 만드는 Private setter를 사용할 수 있으며 코드 내부에서 setter를 사용할 수 있습니다.


3

나는 몇몇 사람들이 이것에 대해 춤을 추 었다고 생각하지만, 나에게 private setter의 가치는 심지어 클래스 내에서도 속성의 동작을 캡슐화 할 수 있다는 것입니다. abhishek이 언급했듯이 속성이 변경 될 때마다 속성 변경 이벤트를 발생시키고 싶지만 속성이 공개적으로 읽기 / 쓰기되는 것을 원하지 않는 경우 개인 설정기를 사용하거나 백업 필드를 수정하는 모든 위치에서 이벤트. 후자는 잊어 버릴 수 있기 때문에 오류가 발생하기 쉽습니다. 이와 관련하여 속성 값을 업데이트하면 일부 계산이 수행되거나 다른 필드가 수정되거나 무언가의 지연 초기화가 발생하는 경우 모든 곳에서 수행하는 것을 기억할 필요없이 개인 setter로 래핑하는 것이 좋습니다. 지원 필드의 사용.


2

캡슐화는 객체의 상태가 정의 된 인터페이스를 통해서만 발생한다는 것을 의미하며, 이로 인해 클래스는이 상태가 항상 유효하고 클래스의 목적에 부합하는지 확인할 수 있습니다.

따라서 어떤 경우에는 필드를 공개적으로 노출하는 것만으로 캡슐화 원칙을 완벽하게 준수합니다. 필드에 대해 가능한 모든 값은 다른 모든 필드의 가능한 다른 모든 값과 함께 유효하므로 프로그래머는 필드를 허용하도록 적극적으로 결정할 수 있습니다. 외부 코드에 의해 자유롭게 조작 될 수 있습니다.

이러한 경우는 대부분 "일반 오래된 데이터"인 클래스로 제한됩니다. 그들은 또한 이와 관련하여별로 흥미롭지 않으므로 충분합니다.

다른 경우, 다른 언어에서는 int getId()값을 얻고 void setId(int val)업데이트 하는 것과 같은 getter 및 setter 메소드가 있습니다.

속성을 사용하면 필드를 읽고 쓰는 데 사용하는 것과 같은 메서드를 통해 읽고 쓰는 데 동일한 구문을 사용할 수 있습니다. 이것은 필수는 아니지만 좋은 구문상의 설탕입니다.

(사실 리플렉션이 작동하는 방식과 DataBinder.Eval필드가 잘 작동하는 경우에도 속성을 갖는 것이 편리 할 수 ​​있기 때문에 이는 또 다른 문제입니다).

private setter가 도입 될 때까지 (실제로 C # 2에서 변경된 것은 동일한 블록에 private setter와 public 또는 protected getter를 갖는 구문입니다) private setter의 작업을 수행하는 private 메서드를 가질 수있었습니다. 개인 세터는 실제로 필요하지 않습니다. 그래도 편리하기 때문에 구문 상 설탕이지만 꽤 유용합니다.

캡슐화는 setter (또는 getter)가 공개, 비공개, 보호 또는 내부인지 여부가 아니라 적절한 지 여부의 문제입니다 . 모든 필드의 기본값으로 시작하여 (그리고 해당 문제에 대해 readonly) 필요에 따라 해당 필드를 변경하는 멤버 (속성 또는 메서드)를 추가하고 변경시 개체가 유효한지 확인합니다 . 이렇게하면 클래스의 불변성 이 유지됩니다. 즉, 해당 클래스 가있을 수있는 유효한 상태 집합을 설명하는 규칙이 깨지지 않습니다 (생성자는 이러한 유효한 상태에서 시작하도록하여 도움을줍니다).

마지막 질문에 대해 불변이라는 것은 클래스에 공개, 보호 또는 내부 setter 없으며 필드를 변경하는 공개, 보호 또는 내부 메서드가 없음을 의미합니다. 이 정도의 정도가 있으며 C #에서는 세 가지 정도가 가능합니다.

  1. 클래스의 모든 인스턴스 필드는 readonly이므로 개인 코드도 변경할 수 없습니다. 불변임이 보장되며 (변경하려는 모든 것은 컴파일되지 않음) 아마도 최적화는 이것의 뒷면에서 수행 될 수 있습니다.

  2. public 멤버가 아무것도 변경하지 않기 때문에 클래스는 외부에서 변경할 수 없지만을 사용 readonly하여 내부에서 변경되지 않는다는 보장은 없습니다.

  3. 일부 상태는 구현 세부 사항으로 변경되지만 클래스는 외부에서 볼 때 변경할 수 없습니다. 예를 들어 필드를 메모 할 수 있으므로 외부에서 가져 오려는 시도는 동일한 값을 가져 오지만 첫 번째 시도는 실제로이를 계산 한 다음 후속 시도에서 검색을 위해 저장합니다.


1

다음 시나리오를 지원하려면 private setter가 필요합니다 (이 경우뿐만 아니라 좋은 이유 하나를 지적해야 함) : 클래스에서 읽기 전용 인 속성이 있습니다. 즉, 클래스 자체 만 변경할 수 있습니다. 하지만 인스턴스를 생성 한 후 변경할 수 있습니다. 바인딩의 경우 PropertyChanged 이벤트를 발생시켜야합니다. 바람직하게는 (개인) 속성 설정자에서 수행해야합니다. 실제로 클래스의 다른 곳에서 PropertyChanged 이벤트를 발생시킬 수 있지만이를 위해 private setter를 사용하는 것은 "좋은 시민권"입니다. 왜냐하면 속성 변경 트리거를 클래스 전체에 배포하지 않고 그대로 유지하기 때문입니다. 재산, 그것이 속한 곳.


1

예, 속성을 사용하여 캡슐화를 사용하고 있지만 캡슐화에는 속성을 읽고 쓰는 방법을 제어하는 ​​것보다 더 많은 뉘앙스가 있습니다. 클래스 외부에서 설정할 속성을 거부하면 견고성과 성능 모두에 유용 할 수 있습니다.

불변 클래스는 생성 된 후에는 변경되지 않는 클래스이므로 속성을 보호하려면 전용 setter (또는 setter 없음)가 필요합니다.

전용 setter는 C # 3에서 도입 된 속성 속기로 더 자주 사용되었습니다. C # 2에서는 setter가 종종 생략되고 설정시 개인 데이터에 직접 액세스됩니다.

이 속성 :

public int Size { get; private set; }

와 같다:

private int _size;
public int Size {
  get { return _size; }
  private set { _size = value; }
}

단, 지원 변수의 이름은 컴파일러에 의해 내부적으로 생성되므로 직접 액세스 할 수 없습니다.

축약 속성을 사용하면 백업 변수에 직접 액세스 할 수 없기 때문에 읽기 전용 속성을 생성하기 위해 전용 setter가 필요합니다.


올바르게 기억 하면 C # 2.0 이전 getset이전 에 다른 액세스 한정자를 가질 수 없었습니다 . 또한 자동 구현 된 속기가 3.0 이었으므로 2.0과 3.0을 혼합하고 있다고 생각합니다.
Anthony Pegram

1

C # 2로 시작된 개인 setter가 필요하다는 것을 이해하지 못합니다.

사용 사례 예 :

클래스 소비자에게 노출하고 싶지 않은 'UserInfo'속성 SessionTokenIDV1을 포함 하는 응용 프로그램 개체의 인스턴스 가 있습니다 .

수업에서 그 값을 설정할 수있는 능력도 필요합니다.

내 솔루션은 표시된대로 속성을 캡슐화하고 setter를 비공개로 설정하여 인스턴스화 코드도 설정하도록 허용하지 않고 세션 토큰의 값을 설정할 수 있도록하는 것이 었습니다.

public class UserInfo
{
   public String SessionTokenIDV1 { get; set; }

}


public class Example
{
  // Private vars
  private UserInfo _userInfo = new UserInfo();

  public string SessionValidV1
  {
    get { return ((_userInfo.SessionTokenIDV1 != null) && (_userInfo.SessionTokenIDV1.Length > 0)) ? "set" : "unset"; }
    private set { _userInfo.SessionTokenIDV1 = value; }
  }
}

편집 : 수정 된 코드 태그 편집 : 예제에 수정 된 오류가 있습니다.


-1

https://www.dotnetperls.com/property에 대한 크레딧 .

개인 setter는 읽기 전용 필드와 동일합니다. 생성자에서만 설정할 수 있습니다. 외부에서 설정하려고하면 컴파일 시간 오류가 발생합니다.

public class MyClass
{
    public MyClass()
    {
        // Set the private property.
        this.Name = "Sample Name from Inside";
    }
     public MyClass(string name)
    {
        // Set the private property.
        this.Name = name;
    }
    string _name;
    public string Name
    {
        get
        {
            return this._name;
        }
        private set
        {
            // Can only be called in this class.
            this._name = value;
        }
    }
}

class Program
{
    static void Main()
    {
        MyClass mc = new MyClass();
        Console.WriteLine(mc.name);

        MyClass mc2 = new MyClass("Sample Name from Outside");
        Console.WriteLine(mc2.name);
    }
}

수업 외부에서 설정을 시도한 경우 아래 스크린 샷을 참조하십시오.

여기에 이미지 설명 입력

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