불변 클래스는 어떻게 만듭니 까?


113

불변 클래스를 만드는 중입니다.
모든 속성을 읽기 전용으로 표시했습니다.

수업에 항목 목록이 있습니다.
속성이 읽기 전용 인 경우 목록을 수정할 수 있습니다.

목록의 IEnumerable을 노출하면 변경할 수 없습니다.
클래스를 불변으로 만들기 위해 따라야하는 기본 규칙이 무엇인지 알고 싶었습니다.


2
Immutability에 대한 Eric Lippert의 블로그 시리즈 , 특히 "kinds of immutability" 항목을 읽을 것을 강력히 권장합니다 . "목록의 IEnumerable을 노출하면 불변으로 만든다"는 귀하의 의견은 나에게 다소 이상하게 보입니다. 그게 무슨 뜻이야?
Jon Skeet

내가 의미하는 바는 목록 (객체에 다른 객체의 목록이있는 경우)에 대한 액세스를 허용하는 것이 아니라 사용자가 IEnumerable을 사용하여 구성원에 액세스 할 수 있도록 허용하는 것입니다. 특정 예에서와 같이 여기에 말하는 목록이지만 모든 데이터 구조가 될 수 있습니다.
Biswanath

1
Eric Lippert의 블로그 시리즈에 대한 Jon Skeet의 링크는 MSDN이 이러한 블로그를 보관할 때 깨졌습니다. "불변의 종류"를 참조하십시오 . 나머지 시리즈는 왼쪽 패널에서 2007 년 12 월 + 2008 년 1 월 미만인 것으로 보입니다.
John Doe

사람들이 일반적으로 용어 혼동 방법에 에릭 Lippert의 블로그 시리즈를 참조하십시오 atomicity, volatility그리고 immutability: 부품 하나 , 2 부3 부 . 이것들은 그의 개인 블로그에서 왔으며 그의 MSDN 게시물보다 초보자에게 더 친숙하다고 생각합니다.
John Doe

답변:


121

나는 당신이 올바른 길을 가고 있다고 생각합니다.

  • 클래스에 주입 된 모든 정보는 생성자에 제공되어야합니다.
  • 모든 속성은 getter 여야합니다.
  • 컬렉션 (또는 배열)이 생성자에 전달되면 호출자가 나중에 수정하지 못하도록 복사해야합니다.
  • 컬렉션을 반환하려면 복사본 또는 읽기 전용 버전을 반환합니다 (예 : ArrayList.ReadOnly 또는 이와 유사한 사용)-이것을 이전 지점과 결합하고 다음 경우에 반환 될 읽기 전용 복사본을 저장할 수 있습니다. 호출자가 액세스), 열거자를 반환하거나 컬렉션에 대한 읽기 전용 액세스를 허용하는 다른 메서드 / 속성을 사용합니다.
  • 멤버 중 하나라도 변경 가능한 경우 여전히 변경 가능한 클래스의 모양을 가질 수 있습니다.이 경우 유지하려는 상태를 복사하고 전체 변경 가능한 객체를 복사하지 않는 한 반환하지 않아야합니다. 호출자에게 돌려주기 전에-또 다른 옵션은 변경 가능한 객체의 변경 불가능한 "섹션"만 반환하는 것입니다. @Brian Rasmussen 덕분에이 점을 확장 할 수 있습니다.

조회 만 할 수있는 래퍼 조회 속성을 작성해야합니까? 그리고 대답 해 주셔서 감사합니다.
Biswanath

5
생성자에 인수로 전달 된 변경 가능한 참조 유형은 복사해야합니다. 그렇지 않으면 발신자는 여전히 상태에 대한 참조를 보유합니다.
Brian Rasmussen

@Brian Rasmussen, 맞습니다.하지만 복사 된 경우에도 제공된 acces.sors에 따라 모든 호출자가 변경 가능한 개체에 액세스 할 수 있습니다. 변경 가능한 객체가 전달되는 경우 클래스는 항상 객체의 다른 복사본 또는 변경 불가능한 섹션을 반환하는 것이 가장 좋습니다
Blair Conrad

@Blair-클래스에 사전이있는 경우 검색에 사용하고 싶습니다. 조회를 수행하는 읽기 전용 속성입니까?
Biswanath

@Biswanath-예, 사전의 값을 변경할 수있는 경우 반환하기 전에 보호해야한다는 경고와 함께 변경하지 않으려면
Blair Conrad

18

변경 불가능하게하려면 모든 속성과 필드가 읽기 전용이어야합니다. 그리고 모든 목록의 항목은 그 자체로 불변이어야합니다.

다음과 같이 읽기 전용 목록 속성을 만들 수 있습니다.

public class MyClass
{
    public MyClass(..., IList<MyType> items)
    {
        ...
        _myReadOnlyList = new List<MyType>(items).AsReadOnly();
    }

    public IList<MyType> MyReadOnlyList
    {
        get { return _myReadOnlyList; }
    }
    private IList<MyType> _myReadOnlyList

}

1
ImmutableList가 더 좋을 것이라고 생각합니다.
Kevin Wong

사용 ImmutableList는 또한 클래스 밀봉 고려
kofifus

ImmutableList가이 사용 사례에 적합하다고 확신하지 않습니다 basic rules to make a class (that contains a list) immutable. ImmutableList 시맨틱은 목록의 사본에 항목을 추가 할 때보다 효율적인 메모리 사용을 가능하게하지만, 나에게는 더 구체적인 사용 사례 인 것 같습니다.
Joe

11

또한 다음 사항에 유의하십시오.

public readonly object[] MyObjects;

readonly 키워드로 표시된 경우에도 변경 불가능하지 않습니다. 인덱스 접근 자별로 개별 배열 참조 / 값을 변경할 수 있습니다.


5

ReadOnlyCollection수업을 사용하십시오 . 그것은에 위치하고있어 System.Collections.ObjectModel공간.

목록 (또는 생성자)을 반환하는 모든 항목에서 목록을 읽기 전용 컬렉션으로 설정합니다.

using System.Collections.ObjectModel;

...

public MyClass(..., List<ListItemType> theList, ...)
{
    ...
    this.myListItemCollection= theList.AsReadOnly();
    ...
}

public ReadOnlyCollection<ListItemType> ListItems
{
     get { return this.myListItemCollection; }
}

1

또 다른 옵션은 내부 컬렉션을 전혀 노출하는 대신 방문자 패턴을 사용하는 것입니다.


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