불변성을 보장하는 것이 속성 대신 필드를 노출시키는 것에 대한 정당성입니까?


10

C #에 대한 일반적인 지침은 항상 공개 필드를 통해 속성을 사용하는 것입니다. 필드를 노출하면 구현 세부 사항을 많이 노출하게됩니다. 속성을 사용하면 해당 세부 정보를 캡슐화하여 코드를 사용하지 못하도록 숨기고 구현 변경 내용은 인터페이스 변경 내용과 분리됩니다.

그러나 readonly키워드를 다룰 때이 규칙에 유효한 예외가 있는지 궁금합니다 . 이 키워드를 퍼블릭 필드에 적용하면 불변성이라는 추가적인 보장을 할 수 있습니다. 이것은 구현 세부 사항 일뿐 아니라 불변성은 소비자가 관심을 가질만한 부분입니다. readonly필드를 사용 하면 공개 계약의 일부가되며 공개 인터페이스를 수정하지 않고도 향후 변경이나 상속으로 인해 깨지지 않는 것입니다. 그것은 부동산이 제공 할 수없는 것입니다.

그렇다면 불변성을 보장하는 것이 합당한 이유 readonly중 어떤 경우에는 속성보다 필드 를 선택해야 합니까?

(명백하게, 나는 클래스의 디자인의 일부로 의미가 있고 계약에 불변성을 포함하려는 의도가있을 때만 현재 필드가 불변이기 때문에 항상 이 선택 을해야한다고 말하지는 않습니다 . 나는 회원이 있어야 할 때 interface또는 게으른 로딩을 원할 때와 같이 그렇지 않은 특정 경우보다는 이것이 정당화 될 수 있는지에 초점을 맞춘 답변에 주로 관심이 있습니다 .)



1
@gnat "ReadOnly Property"은 명확하게 설명하기 위해 VB.NET 용어를 사용 합니다. 즉, 읽기 전용 필드가 아닌 설정자가없는 속성을 의미 합니다. 내 질문의 목적 상, 그 질문과 비교하는 두 가지 옵션은 동등합니다. 둘 다 속성을 사용하고 있습니다.
벤 Aaronson

답변:


6

공개 정적 읽기 전용 필드는 확실합니다. 명명 된 상수 개체를 원하지만 const키워드를 사용할 수없는 경우와 같은 특정 상황에 권장됩니다 .

읽기 전용 멤버 필드는 조금 까다 롭습니다. 공용 세터가없는 속성에 비해 이점이 크지 않으며 주요 단점이 있습니다. 필드는 인터페이스의 멤버 일 수 없습니다. 따라서 구체적인 유형 대신 인터페이스에 대해 작동하도록 코드를 리팩터링하기로 결정한 경우 읽기 전용 필드를 공용 게터가있는 특성으로 변경해야합니다.

상속 된 클래스가 지원 필드에 액세스 할 수 없으면 보호 된 setter가없는 공용 비가 상 속성은 상속으로부터 보호합니다. 기본 클래스에서 해당 계약을 완전히 시행 할 수 있습니다.

이 경우 클래스의 공용 인터페이스를 변경하지 않고 멤버의 "불변성"을 변경할 수없는 것은 큰 장애물이 아닙니다. 일반적으로 공개 필드를 속성으로 변경하려는 경우 처리해야 할 두 가지 경우가 있다는 점을 제외하고는 원활하게 진행됩니다.

  1. 다음과 같이 해당 객체의 멤버에 쓰는 것은 필드 인 object.Location.X = 4경우에만 가능 Location합니다. 읽기 전용 구조체는 수정할 수 없으므로 읽기 전용 필드와 관련이 없습니다. (이것은 Location가치 유형 이라고 가정합니다. 그렇지 않으면이 문제는 readonly그런 종류의 것을 막지 않기 때문에 어쨌든 적용 되지 않습니다.)
  2. 로 값을 전달하는 방법에 대한 모든 호출 out또는 ref. 다시 말하지만,이, 읽기 전용 필드에 대한 정말 관련이 없습니다 때문에 out그리고ref 매개 변수를 수정하는 경향, 그리고 밖으로 나 심판과 같은 읽기 전용 값을 전달 어쨌든 컴파일러 오류입니다.

즉, 읽기 전용 필드를 읽기 전용 속성으로 변환하면 이진 호환성이 손상되지만 다른 소스 코드는이 변경 사항을 처리하기 위해 변경없이 다시 컴파일하면됩니다. 그렇게하면 보증이 깨지기 쉬워집니다.

나는 readonly멤버 필드에 어떤 이점도 보지 못하고 , 인터페이스에 그런 종류의 물건을 가질 수 없다는 것은 그것을 사용하지 않을 것이라는 단점이 충분합니다.


관심이없는 이유 무엇입니까? 공개 정적 읽기 전용 필드는 괜찮습니까? 인스턴스 메소드를 배제하면 불변의 필드 (히트 카운팅, 게으른 로딩 등)의 속성에 대한 대부분의 사용 사례가 제거되기 때문입니까?
벤 애런 슨

공용 읽기 전용 필드와 읽기 전용 속성의 주요 단점은 사라졌습니다. 정적 멤버는 인터페이스의 일부가 될 수 없으므로 유사한 기반에 있습니다. 읽기 전용 정적 속성은 초기화 될 저장소가 필요하거나 호출 될 때마다 반환 값을 다시 작성해야하는 반면, 읽기 전용 필드는 구문이 더 간단하고 정적 생성자에 의해 초기화됩니다. 따라서 공개 정적 읽기 전용 필드는 일반적으로 필드를 노출하는 데 따르는 단점이 없지만 JIT에 의해 더 큰 최적화 가능성이 있다고 생각합니다.
Erik

2

내 경험으로는 readonly키워드가 약속 한 마법이 아닙니다.

예를 들어 생성자가 단순했던 클래스가 있습니다. 사용법 (및 일부 클래스 속성 / 필드가 생성 후 변경 불가능하다는 사실)을 고려할 때 중요하지 않다고 생각할 수 있으므로 readonly키워드 를 사용했습니다 .

나중에 클래스가 더 복잡해지고 생성자도 복잡해집니다. (이것은 실험적이거나 범위 / 제어에서 속도가 충분히 확대되는 프로젝트에서 발생하지만 어떻게 든 작동하게 만들어야한다고 가정 해 봅시다.) readonly생성자 내에서만 수정할 수 있는 필드를 찾을 수 있습니다. 해당 메소드가 생성자에서만 호출되는 경우에도 메소드에서 수정할 수 없습니다.

이 기술적 인 한계는 C #의 설계자에 의해 인정되었으며 향후 버전에서 수정 될 수 있습니다. 그러나 그것이 고정 될 때까지 사용 readonly은 더 제한적이며 나쁜 코딩 스타일 (생성자 메서드에 모든 것을 넣음)을 장려 할 수 있습니다.

다시 말해, readonly공개 설정자 이외의 속성도 "완전히 초기화 된 개체"를 보장 하지 않습니다. 다시 말해서, "완전히 초기화 된"의 의미와 의도하지 않은 사용으로부터 그것을 보호하는 방법을 결정하는 것은 클래스의 설계자이며, 그러한 보호는 일반적으로 절대 안전하지 않습니다.


1
나는 생성자를 간단하게 유지하는 것을 선호한다 -brendan.enrick.com/post/… , blog.ploeh.dk/2011/03/03/InjectionConstructorsConstructors 는 실제로 단순 해야하므로, 읽기 전용은 좋은 코딩 스타일을 장려해야한다
AlexFoxGill

1
생성자는 readonly필드 를 다른 메소드에 매개 변수 out또는 ref매개 변수 로 전달할 수 있습니다. 그러면 원하는대로 수정할 수 있습니다.
supercat

1

필드는 항상 구현 세부 사항입니다. 구현 세부 사항을 공개하고 싶지 않습니다.

소프트웨어 엔지니어링의 기본 원리는 향후 요구 사항이 무엇인지 모른다는 것입니다. readonly오늘날 귀하의 분야는 좋을지 모르지만 미래의 요구 사항의 일부가 될 것이라고 제안하는 것은 없습니다. 내일 해당 필드에 액세스하는 횟수를 결정하기 위해 적중 카운터를 구현해야하는 경우 어떻게해야합니까? 하위 클래스가 필드를 재정의하도록 허용하려면 어떻게해야합니까?

속성은 사용하기 쉽고 공용 필드보다 훨씬 유연하여 c #을 내 언어로 선택하고 클래스에서 공용 읽기 전용 필드를 사용하는 단일 사용 사례를 생각할 수 없습니다. 추가 메소드 호출을 수행 할 수 없을 정도로 성능이 너무 타이트한 경우 다른 언어를 사용하고있을 것입니다.

우리가해서 할 수 언어로 무언가를 우리가 의미하는 것은 아니다 한다 언어와 뭔가.

실제로 언어 디자이너가 필드를 공개하는 것을 후회하는지 궁금합니다. 내 코드에서 비 const 공용 필드 사용을 고려한 마지막 시간을 기억할 수 없습니다.


1
나는 미래의 유연성을 구축하는 것의 중요성을 이해하지만 Rational, 공개, 불변 NumeratorDenominator회원 과 같은 클래스를 작성하면 해당 회원이 게으른로드 또는 적중 카운터를 요구하지 않을 것이라고 확신 할 수 있습니다. 비슷한?
벤 Aaronson

하지만 당신은 구현이 사용하는 것을 확신 할 수 있습니다 float에 대한 유형 NumeratorDenominator로 변경 될 필요가 없습니다 doubles?
Stephen

1
음, 어은, 아니, 그들은 확실히 어느 쪽도 없을 것 float아니다 double. 그들은해야한다 int, long또는 BigInteger. 어쩌면 변경해야 할 수도 있지만 공개 인터페이스에서도 변경해야 할 수도 있으므로 실제로 속성을 사용하면 세부 사항을 캡슐화하지 않아도됩니다.
벤 Aaronson

-3

아닙니다. 정당화되지 않습니다.

정당화가 아닌 불변의 보증으로 읽기 전용을 사용하는 것은 해킹과 같습니다.

읽기 전용은 변수가 정의 될 때 생성자에 의해 값이 할당됨을 의미합니다.

나는 그것이 나쁜 습관이라고 생각합니다

불변성을 보장하려면 인터페이스를 사용하는 것이 단점보다 더 많은 인터페이스를 사용하십시오.

간단한 인터페이스 예 : 여기에 이미지 설명을 입력하십시오


1
"인터페이스 사용"어떻게?
벤 애런 슨
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.