C #에서 속성을 사용하지 않아야하는 이유는 무엇입니까?


102

그의 훌륭한 저서 인 CLR Via C #에서 Jeffrey Richter는 속성을 좋아하지 않으며 사용하지 말 것을 권장한다고 말했습니다. 그는 어떤 이유를 줬지만 나는 정말로 이해하지 못한다. 왜 내가 속성을 사용하거나 사용하지 말아야하는지 설명해 줄 수 있습니까? 자동 속성을 사용하는 C # 3.0에서 이것이 변경됩니까?

참고로 Jeffrey Richter의 의견을 추가했습니다.

• 속성은 읽기 전용이거나 쓰기 전용 일 수 있습니다. 필드 액세스는 항상 읽고 쓸 수 있습니다. 속성을 정의하는 경우 get 및 set 접근 자 메서드를 모두 제공하는 것이 가장 좋습니다.

• 속성 메서드에서 예외가 발생할 수 있습니다. 필드 액세스는 예외를 발생시키지 않습니다.

• 속성은 out 또는 ref 매개 변수로 메서드에 전달할 수 없습니다. 필드는 할 수 있습니다. 예를 들어 다음 코드는 컴파일되지 않습니다.

using System;
public sealed class SomeType
{
   private static String Name 
   {
     get { return null; }
     set {}
   }
   static void MethodWithOutParam(out String n) { n = null; }
   public static void Main()
   {
      // For the line of code below, the C# compiler emits the following:
      // error CS0206: A property or indexer may not
      // be passed as an out or ref parameter
      MethodWithOutParam(out Name);
   }
}

• 속성 메서드를 실행하는 데 시간이 오래 걸릴 수 있습니다. 필드 액세스는 항상 즉시 완료됩니다. 속성을 사용하는 일반적인 이유는 스레드 동기화를 수행하기위한 것이므로 스레드를 영원히 중지 할 수 있으므로 스레드 동기화가 필요한 경우 속성을 사용하지 않아야합니다. 이러한 상황에서는 방법이 선호됩니다. 또한 클래스에 원격으로 액세스 할 수있는 경우 (예 : 클래스가 System.MashalByRefObject에서 파생 됨) 속성 메서드 호출이 매우 느리므로 속성보다 메서드가 선호됩니다. 제 생각에는 MarshalByRefObject에서 파생 된 클래스는 속성을 사용해서는 안됩니다.

• 연속적으로 여러 번 호출되는 경우 속성 메서드는 매번 다른 값을 반환 할 수 있습니다. 필드는 매번 동일한 값을 반환합니다. System.DateTime 클래스에는 현재 날짜와 시간을 반환하는 readonly Now 속성이 있습니다. 이 속성을 쿼리 할 때마다 다른 값이 반환됩니다. 이것은 실수이며 Microsoft는 Now를 속성 대신 메서드로 만들어 클래스를 수정할 수 있기를 바랍니다.

• 속성 방법은 관찰 가능한 부작용을 일으킬 수 있습니다. 필드 액세스는 절대하지 않습니다. 즉, 유형의 사용자는 유형의 다른 동작을 인식하지 않고 자신이 선택한 순서대로 유형에 정의 된 다양한 속성을 설정할 수 있어야합니다.

• 속성 메서드에는 추가 메모리가 필요하거나 실제로 객체 상태의 일부가 아닌 항목에 대한 참조를 반환 할 수 있으므로 반환 된 객체를 수정해도 원래 객체에는 영향을주지 않습니다. 필드를 쿼리하면 항상 원래 개체 상태의 일부가 보장되는 개체에 대한 참조가 반환됩니다. 복사본을 반환하는 속성으로 작업하는 것은 개발자에게 매우 혼란 스러울 수 있으며이 특성은 종종 문서화되지 않습니다.


11
저는 'C #을 통한 CLR'의 3 판을 소유하고 있으며 242 페이지에서 Richter 씨는 개인적으로 속성을 좋아하지 않는다고 말하지만 결코 사용하지 않는 것이 좋습니다. 이것을 읽은 책 버전과 페이지 번호를 인용하십시오.
kirk.burleson

답변:


173

Jeff가 속성을 싫어하는 이유는 속성이 필드처럼 보이기 때문입니다. 따라서 차이점을 이해하지 못하는 개발자는 실행 비용이 저렴할 것이라고 가정하고 해당 속성을 필드 인 것처럼 취급합니다.

개인적으로 나는이 특별한 점에 대해 그와 동의하지 않는다. 속성이 클라이언트 코드를 동등한 메서드 호출보다 훨씬 더 읽기 쉽게 만든다는 것을 발견했다. 나는 개발자가 속성이 기본적으로 위장 된 방법이라는 것을 알아야한다는 데 동의합니다.하지만 개발자를 교육하는 것이 방법을 사용하여 코드를 읽기 어렵게 만드는 것보다 낫다고 생각합니다. (특히, 동일한 명령문에서 여러 getter 및 setter가 호출되는 Java 코드를 보았을 때 동등한 C # 코드가 훨씬 더 읽기 쉽다는 것을 알고 있습니다. Demeter의 법칙은 이론적으로는 모두 매우 훌륭하지만 때로는 foo.Name.Length실제로는 그렇습니다. 사용하기에 옳은 것 ...)

(아니요, 자동으로 구현 된 속성은 실제로이 사항을 변경하지 않습니다.)

이것은 확장 방법을 사용하는 것에 대한 주장과 약간 비슷합니다. 추론은 이해할 수 있지만 실질적인 이점 (아주 드물게 사용되는 경우)이 제 생각에는 단점보다 큽니다.


답변 해 주셔서 감사합니다! 확장 메서드 사용에 대한 논쟁에 대해 : Jeffrey Richter의 주제에 대해 이야기하고 있습니까?
abatishchev

@abatishchev : 확장 메서드에 대한 일반적인 요점 일뿐입니다. 속성과 직접 관련이 없습니다.
Jon Skeet

나는 더 멀리 갈 것입니다. 성능 측면을 제외하고는 프로그래머가 필드 또는 속성인지 알아야하는 이유를 알 수 없습니다. 그는 그것을 객체 인스턴스의 STATE를 지정하는 인스턴스의 속성으로 생각해야하며, 객체 구현은 (클래스의 계약 내에서) 상태에 대한 모든 수정을 처리해야합니다. 따라서 속성은 어떤 경우에는 필드가 될 수도 있고 클래스 구현의 재 설계가 완료되면 다른 필드의 필드가 될 수도 있습니다. 그런 다음 필드 또는 부동산 사이를 결정하는 것은 국가가 일관성을 유지하기 위해 얼마나 많은 보호를 필요로 하는가의 문제입니다.
TheBlastOne 2011-08-10

1
@PatrickFromberg : 분명히 읽기 전용 필드를 사용하는 많은 양의 코드를 놓쳤습니다. 속성이 가변성을 의미한다는 것은 말할 것도 없습니다. 나는 종종 읽기 전용 속성을 지원하는 읽기 전용 필드를 가지고 있습니다. 이것이 나쁜 것이라고 생각하십니까?
Jon Skeet

1
@Patrick : 아니요, API를 구현에서 분리하는 이점이 있습니다. 나중에 속성이 필드에서 계산되는 방식을 변경할 수 있습니다 (예 : 한 필드에서 두 개의 관련 속성을 계산하기 위해).
Jon Skeet 2014

34

글쎄, 그의 주장을 하나씩 살펴 보자.

속성은 읽기 전용이거나 쓰기 전용 일 수 있습니다. 필드 액세스는 항상 읽고 쓸 수 있습니다.

액세스를보다 세밀하게 제어 할 수 있기 때문에 속성에 유리합니다.

속성 메서드는 예외를 throw 할 수 있습니다. 필드 액세스는 예외를 발생시키지 않습니다.

이것은 대부분 사실이지만 초기화되지 않은 개체 필드에서 메서드를 매우 잘 호출하고 예외가 throw 될 수 있습니다.

• 속성은 out 또는 ref 매개 변수로 메서드에 전달할 수 없습니다. 필드는 할 수 있습니다.

공정한.

• 속성 메서드를 실행하는 데 시간이 오래 걸릴 수 있습니다. 필드 액세스는 항상 즉시 완료됩니다.

시간이 거의 걸리지 않을 수도 있습니다.

• 연속적으로 여러 번 호출되는 경우 속성 메서드는 매번 다른 값을 반환 할 수 있습니다. 필드는 매번 동일한 값을 반환합니다.

사실이 아니다. 필드의 값이 변경되지 않았는지 어떻게 알 수 있습니까 (다른 스레드에 의해 가능)?

System.DateTime 클래스에는 현재 날짜와 시간을 반환하는 readonly Now 속성이 있습니다. 이 속성을 쿼리 할 때마다 다른 값이 반환됩니다. 이것은 실수이며 Microsoft는 Now를 속성 대신 메서드로 만들어 클래스를 수정할 수 있기를 바랍니다.

실수라면 사소한 것입니다.

• 속성 방법은 관찰 가능한 부작용을 일으킬 수 있습니다. 필드 액세스는 절대하지 않습니다. 즉, 유형의 사용자는 유형의 다른 동작을 인식하지 않고 자신이 선택한 순서대로 유형에 정의 된 다양한 속성을 설정할 수 있어야합니다.

공정한.

• 속성 메서드에는 추가 메모리가 필요하거나 실제로 객체 상태의 일부가 아닌 항목에 대한 참조를 반환 할 수 있으므로 반환 된 객체를 수정해도 원래 객체에는 영향을주지 않습니다. 필드를 쿼리하면 항상 원래 개체 상태의 일부가 보장되는 개체에 대한 참조가 반환됩니다. 복사본을 반환하는 속성으로 작업하는 것은 개발자에게 매우 혼란 스러울 수 있으며이 특성은 종종 문서화되지 않습니다.

대부분의 항의는 자바의 게터와 세터에 대해서도 언급 될 수 있었으며, 실제로 그러한 문제없이 꽤 오랫동안 겪었습니다.

대부분의 문제는 더 나은 구문 강조 표시 (즉, 필드와 속성을 구별)로 해결할 수 있으므로 프로그래머가 무엇을 기대해야하는지 알 수 있습니다.


3
"더 나은 구문 강조 표시로 문제를 해결할 수 있습니다 . " : 공용 필드를 얼마나 자주 사용하십니까? 개인 필드는 일반적으로 다른 스타일 (예 : _field. 아니면 그냥 소문자 field.
Steven Jeuris 2011 년

18

나는 책을 읽지 않았고 당신이 이해하지 못하는 부분을 인용하지 않았으므로 추측해야 할 것입니다.

어떤 사람들은 코드가 놀라운 일을 할 수 있기 때문에 속성을 싫어합니다.

를 입력 Foo.Bar하면 일반적으로 읽는 사람들은 이것이 단순히 Foo 클래스의 멤버 필드에 액세스하는 것으로 예상합니다. 저렴하고 거의 무료이며 결정 론적입니다. 반복해서 호출 할 수 있고 매번 같은 결과를 얻을 수 있습니다.

대신 속성을 사용하면 실제로 함수 호출 일 수 있습니다. 무한 루프 일 수 있습니다. 데이터베이스 연결을 열 수 있습니다. 액세스 할 때마다 다른 값을 반환 할 수 있습니다.

Linus가 C ++를 싫어하는 이유와 비슷한 주장입니다. 당신의 코드는 독자들에게 놀랍게 작용할 수 있습니다. 그는 연산자 오버로딩을 싫어 a + b합니다. 반드시 단순한 추가를 의미하지는 않습니다. C # 속성처럼 매우 복잡한 작업을 의미 할 수 있습니다. 부작용이있을 수 있습니다. 그것은 무엇이든 할 수 있습니다.

솔직히 이것은 약한 주장이라고 생각합니다. 두 언어 모두 이와 같은 것으로 가득 차 있습니다. (C #에서도 연산자 오버로딩을 피해야합니까? 결국 동일한 인수를 사용할 수 있습니다.)

속성은 추상화를 허용합니다. 우리는 무언가가 일반 필드 인 것처럼 가장 하여 마치 하나 인 것처럼 사용할 수 있으며 뒤에서 일어나는 일에 대해 걱정할 필요가 없습니다.

그것은 일반적으로 좋은 것으로 간주되지만 분명히 의미있는 추상화를 작성하는 프로그래머에 의존합니다. 귀하의 속성 필드처럼 작동 해야 합니다. 부작용이 없어야하며 비싸거나 안전하지 않은 작업을 수행해서는 안됩니다. 우리 는 그것들 을 필드 라고 생각할 수 있기를 원합니다 .

그러나 나는 그것들이 완벽하지 않다고 생각하는 또 다른 이유가 있습니다. 다른 함수에 대한 참조로 전달할 수 없습니다.

필드를로 전달 ref하면 호출 된 함수가 직접 액세스 할 수 있습니다. 함수는 델리게이트로 전달되어 호출 된 함수가 직접 액세스 할 수 있습니다.

속성 ... 할 수 없습니다.

짜증 난다.

그러나 그것이 속성이 악하거나 사용되어서는 안된다는 것을 의미하지는 않습니다. 여러 가지 목적으로 훌륭합니다.


3
내 주장은 시작하는 필드라고 가정해서는 안된다는 것입니다. 다른 클래스에서 호출하는 경우에는 비공개 여야하므로 상수가 아닌 필드에 액세스 할 수 없어야하기 때문입니다. (당신에게 알려주는 명명 규칙도 있습니다.)
Jon Skeet

1
네, 동의합니다. 주장은 "나는이 구문이 필드에만 사용되는 것에 익숙하다. 따라서 다른 경우를 포함하도록 확장하는 것은 나쁘다"로 요약되는 것 같다. 그리고 분명한 대답은 "그럼 다른 경우를 다루는 데 익숙해지면 나쁘지 않을 것입니다"입니다. ;)
jalf

.net 언어가 클래스가 속성을 ref매개 변수 로 노출하는 표준 수단을 제공하기를 바랍니다 . 특수 속성 Foo을 가진 폼 의 멤버 (예 void Foo<T>(ActionByRef<Point,T> proc, ref T param):)이며 컴파일러 thing.Foo.X+=someVar;Foo((ref Point it, ref int param)=>it.X += param, ref someVar);. 람다는 정적 대리자이므로 클로저가 필요하지 않으며 개체 사용자는 속성을 지원하는 저장 위치를 ​​정품 ref매개 변수 로 사용할 수 있습니다 (다른 메서드에 ref매개 변수 로 전달할 수 있음 ).
supercat

손으로 람다를 작성하면 정말 이상한 모양의 소스 코드가 생성되지만 컴파일러가 변환을 수행하도록하는 것이 도움이되는 이유입니다. 클래스가 "callback-by-ref"속성을 노출하는 코드는 상당히 합리적입니다. 코드는 호출자 측에서만 추악합니다 (변환이 없음).
supercat

속성은 멤버로 위장한 함수 호출이므로 클래스의 공용 함수를 전달할 수있는 것보다 더 이상 참조로 전달할 수 없습니다. 그렇게하려는 경우 언제든지 공개 멤버를 사용할 수 있습니다. 속성은 스마트 멤버이며 설정에 전달 된 잘못된 데이터에 대해 예외를 throw 할 수 있습니다.
Diceyus 2017-06-22

17

2009 년에이 조언은 Who Moved My Cheese 품종을 헐뜯는 것처럼 보였습니다 . 오늘날, 그것은 거의 우스꽝스럽게 쓸모가 없습니다.

많은 답변이 발끝으로 튀어 나오는 것처럼 보이지만 정면으로 다루지는 않는 매우 중요한 점 중 하나는 이러한 속성의 "위험" 이 프레임 워크 디자인의 의도적 인 부분이라는 것입니다!

예, 속성은 다음을 수행 할 수 있습니다.

  • getter 및 setter에 대해 다른 액세스 수정자를 지정하십시오. 이것은 분야에 비해 장점 입니다. 일반적인 패턴은 공개 getter와 보호 또는 내부 setter를 갖는 것입니다. 이는 필드만으로는 달성 할 수없는 매우 유용한 상속 기술입니다.

  • 예외를 던집니다. 현재까지 이것은 특히 데이터 바인딩 개념이 포함 된 UI 프레임 워크로 작업 할 때 가장 효과적인 유효성 검사 방법 중 하나로 남아 있습니다. 필드 작업을 할 때 개체가 유효한 상태로 유지되도록하는 것이 훨씬 더 어렵습니다.

  • 실행하는 데 오랜 시간이 걸립니다. 여기서 유효한 비교는 필드가 아닌 똑같이 긴 메서드 를 사용하는 것 입니다. 한 저자의 개인적 선호 외에 "방법이 선호 됨"이라는 문구에 대한 근거는 제공되지 않습니다.

  • 후속 실행에서 getter에서 다른 값을 반환합니다. 이것은 / 호출 후 필드의 값이 이전 값과 거의 다를 것이 보장되고 예측할 수없는 필드 가있는 ref/ out매개 변수 의 장점을 칭찬하는 지점에 매우 근접한 농담처럼 보입니다 .refout

    우리가 어떤 심성 커플 링 단일 스레드 액세스의 경우 특정에 대해 이야기 (실제적으로 교육)하는 경우,있어 꽤 잘 이해 가 가시 상태 변경 부작용이 그냥 나쁜 속성 디자인 있다는, 어쩌면 내 기억이다 페이딩이지만 DateTime.Now매번 동일한 가치가 나올 것으로 예상하고 사용하는 사람들의 예를 기억할 수없는 것 같습니다 . 적어도 그들이 가설과 같이 심하게 망쳐 놓지 않았을 경우는 없습니다 DateTime.Now().

  • 눈에 띄는 부작용을 유발합니다. 물론 속성이 처음에 언어 기능으로 발명 된 이유입니다. Microsoft의 자체 Property Design 지침에 따르면 setter 순서는 중요하지 않습니다 . 그렇지 않으면 시간적 결합을 의미 합니다. 확실히 필드와 시간적 결합을 달성 할 수는 없지만, 일부 메서드가 실행될 때까지 필드만으로는 의미있는 동작을 전혀 발생시킬 수 없기 때문입니다.

    속성 접근 자는 작업이 수행되기 전에 개체를 유효한 상태로 강제 설정하여 특정 유형의 시간적 결합을 방지 하는 데 실제로 도움이 될 수 있습니다. 예를 들어 클래스에 a StartDateEndDate 다음 설정, EndDate(가) 이전에 StartDate강제 할 수 StartDate뿐만 아니라 다시. 이벤트 기반 사용자 인터페이스의 명백한 예를 포함하여 다중 스레드 또는 비동기 환경에서도 마찬가지입니다.

속성이 수행 할 수있는 기타 작업은 포함 할 수없는 필드입니다.

  • 지연 로딩 , 초기화 순서 오류를 방지하는 가장 효과적인 방법 중 하나입니다.
  • 변경 알림 .MVVM 아키텍처의 .
  • 상속 , 예를 들어 추상 정의Type 또는 Name파생 클래스 은 흥미롭지 만 그럼에도 불구하고 자신에 대한 지속적인 메타 데이터를 제공 할 수 있습니다.
  • 차단위의 덕분에 .
  • 인덱서 , COM interop으로 작업해야했던 모든 사람과 불가피한 Item(i)호출 분출은 멋진 것으로 인식 할 것입니다.
  • PropertyDescriptor로 작업 디자이너의 작성 및 일반적으로 XAML 프레임 워크 필수적이다.

Richter는 분명히 다작의 저자이며 CLR 및 C #에 대해 많이 알고 있지만, 그가 원래이 조언을 썼을 때처럼 보입니다. 그는 단지 오래된 습관을 버리고 싶지 않았고 C #의 관습을 받아들이는 데 어려움을 겪고있었습니다 (예 : C ++와 비교).

이것이 의미하는 바는 그의 "유해한 것으로 간주되는 속성"주장은 본질적으로 단일 진술로 요약됩니다. 속성은 필드처럼 보이지만 필드처럼 작동하지 않을 수도 있습니다. 그리고 성명서의 문제 는 사실이 아니 거나 기껏해야 오해의 소지가 있다는 것입니다. 속성 필드처럼 보이지 않습니다 . 적어도 필드처럼 보이지 않아야 합니다.

이 두 가지 매우 다른 CLR 언어에 의해 공유 유사한 규칙과 C #에서 강력한 코딩 규칙, 그리고 당신이 그들을 따르지 않는 경우의 FxCop은 비명합니다 :

  1. 필드한다 항상 개인 수 결코 공개.
  2. 필드는 camelCase로 선언해야합니다. 속성은 PascalCase입니다.

따라서 Foo.Bar = 42속성 접근 자인지 필드 접근 자 인지 에 대한 모호성이 없습니다 . 속성 접근 자이며 다른 메서드처럼 취급되어야합니다. 느릴 수 있고 예외가 발생할 수 있습니다. 이것이 추상화 의 특성입니다 . 반응하는 방법을 선언하는 클래스의 재량에 달려 있습니다. 클래스 디자이너는 최소한의 놀라움의 원칙을 적용해야하지만 호출자는 속성이 주석에 표시된 것을 제외하고는 어떤 것도 가정해서는 안됩니다. 그것은 의도적 인 것입니다.

속성의 대안은 모든 곳에서 getter / setter 메서드입니다. 이것이 Java 접근 방식이며 처음부터 논란 이되었습니다 . 그것이 당신의 가방이라면 괜찮지 만 우리가 .NET 진영에 들어가는 방식은 아닙니다. Fowler가 Syntactic Noise 라고 부르는 것을 피하기 위해 적어도 정적으로 형식화 된 시스템의 범위 내에서 시도 합니다. 우리는 추가 괄호, 추가 get/ set사마귀 또는 추가 메서드 서명을 원하지 않습니다. 명확성을 잃지 않고 피할 수있는 경우가 아닙니다.

당신이 좋아하는 것을 말하되, foo.Bar.Baz = quux.Answers[42]는 항상보다 읽기 쉬울 것 foo.getBar().setBaz(quux.getAnswers().getItem(42))입니다. 그리고 하루에 수천 줄을 읽을 때 차이가 있습니다.

(그리고 위 단락에 대한 당신의 자연스러운 반응이 "읽기 어렵지만 여러 줄로 나누면 더 쉬울 것"이라고 말하는 것이면 , 요점 을 완전히 놓쳤다 고 말하는 것이 유감입니다 .)


11

일반적으로 속성을 사용하지 않아야하는 이유를 알 수 없습니다.

C # 3+의 자동 속성은 구문을 약간 단순화합니다.


그 책의 215-216 페이지를 읽으십시오. 나는 당신이 Jeffrey Richter가 누군지 알고 있다고 확신합니다!
Quan Mai

나는 (C #을 통한 CLR, 2nd Ed.) 그의 입장에 동의하지 않으며 속성을 사용하지 않는 실제 이유를 보지 못했습니다!
abatishchev

좋은 책이지만 지금은 저자의 말에 동의하지 않습니다.
Konstantin Tarkus

저자가 속성을 사용하지 말라고 제안한 곳은 정확히 어디입니까? p.215-217에서 아무것도 발견하지 못했습니다
Konstantin Tarkus

내 질문에 Jeffrey의 의견을 추가했습니다. :). 인쇄판의 215-216 페이지에서 찾을 수 있습니다. :)
Quan Mai

9

한 사람의 의견 일뿐입니다. 나는 꽤 많은 C # 책을 읽었고 "속성을 사용하지 말라"고 말하는 사람을 아직 보지 못했다.

개인적으로 속성은 C #의 가장 좋은 점 중 하나라고 생각합니다. 원하는 메커니즘을 통해 상태를 노출 할 수 있습니다. 무언가를 처음 사용할 때 느리게 인스턴스화 할 수 있으며 값 설정 등에 대한 유효성 검사를 수행 할 수 있습니다. 속성을 사용하고 작성할 때 속성을 훨씬 더 좋은 구문 인 setter와 getter로 생각합니다.

속성에 대한 경고는 몇 가지가 있습니다. 하나는 아마도 속성의 오용이고 다른 하나는 미묘 할 수 있습니다.

첫째, 속성은 메서드 유형입니다. 대부분의 클래스 사용자는 속성이 상당히 가벼울 것으로 기대하기 때문에 속성에 복잡한 논리를 배치하면 놀랍습니다.

public class WorkerUsingMethod
{
   // Explicitly obvious that calculation is being done here
   public int CalculateResult()
   { 
      return ExpensiveLongRunningCalculation();
   }
}

public class WorkerUsingProperty
{
   // Not at all obvious.  Looks like it may just be returning a cached result.
   public int Result
   {
       get { return ExpensiveLongRunningCalculation(); }
   }
}

이러한 경우에 방법을 사용하면 구분하는 데 도움이됩니다.

둘째, 더 중요한 것은 디버깅하는 동안 속성을 평가하면 속성이 부작용을 일으킬 수 있다는 것입니다.

다음과 같은 속성이 있다고 가정합니다.

public int Result 
{ 
   get 
   { 
       m_numberQueries++; 
       return m_result; 
   } 
}

이제 너무 많은 쿼리가 작성 될 때 발생하는 예외가 있다고 가정하십시오. 디버깅을 시작하고 디버거에서 속성을 롤오버하면 어떤 일이 발생하는지 추측하십시오. 나쁜 것들. 이것을 피하십시오! 속성을 살펴보면 프로그램의 상태가 변경됩니다.

이것들은 내가 가진 유일한 경고입니다. 부동산의 이점이 문제보다 훨씬 크다고 생각합니다.


6

그 이유는 매우 구체적인 맥락에서 주어 졌을 것입니다. 일반적으로 다른 방법입니다. 속성을 사용하면 클라이언트에 영향을주지 않고 클래스의 동작을 변경할 수있는 추상화 수준을 제공하므로 속성을 사용하는 것이 좋습니다.


+1은 클라이언트와 클래스 속성 간의 "계약"의 중요성을 암시 적으로 강조합니다.
TheBlastOne 2011-08-10

6

Jeffrey Richter의 의견에 대한 세부 사항을 선택하는 데 도움이되지 않습니다.

속성은 읽기 전용이거나 쓰기 전용 일 수 있습니다. 필드 액세스는 항상 읽고 쓸 수 있습니다.

잘못됨 : 필드는 읽기 전용으로 표시되어 객체의 생성자 만 쓸 수 있습니다.

속성 메서드는 예외를 throw 할 수 있습니다. 필드 액세스는 예외를 발생시키지 않습니다.

잘못됨 : 클래스 구현은 필드의 액세스 수정자를 공개에서 비공개로 변경할 수 있습니다. 런타임에 비공개 필드를 읽으려고하면 항상 예외가 발생합니다.


5

나는 Jeffrey Richter의 의견에 동의하지 않지만 그가 부동산을 좋아하지 않는 이유를 짐작할 수 있습니다 (저는 그의 책을 읽지 않았습니다).

비록 속성은 메서드 (구현 측면)와 비슷하지만 클래스 사용자로서 속성은 공용 필드처럼 "다소"동작 할 것으로 예상합니다. 예 :

  • 속성 getter / setter 내부에서 진행되는 시간 소모적 인 작업이 없습니다.
  • 속성 getter에는 부작용이 없습니다 (여러 번 호출해도 결과가 변경되지 않음).

불행히도 나는 그렇게 행동하지 않는 속성을 보았다. 그러나 문제는 자산 자체가 아니라이를 구현 한 사람들입니다. 그래서 그것은 약간의 교육이 필요합니다.


1
+1은 깨끗한 계약의 중요성을 강조하기 때문입니다. 각 참조에 대해 정기적으로 다른 값을 반환하는 겉보기 읽기 전용 속성을 갖는 것은 읽기 쓰기 속성입니다. 그냥 자체 값이 아니라 다른 인스턴스 변수 (직간접 적)에 기록합니다. 그것은 나쁜 스타일은 아니지만 문서화되어야합니다 (또는 계약의 암시 적 부분이어야합니다).
TheBlastOne 2011-08-10

4

속성을 사용하지 않는 것을 고려할 때가 있는데 그것은 .Net Compact Framework 코드를 작성하는 것입니다. CF JIT 컴파일러는 데스크톱 JIT 컴파일러와 동일한 최적화를 수행하지 않으며 단순 속성 접근자를 최적화하지 않습니다. 따라서이 경우 단순 속성을 추가하면 공용 필드를 사용하는 동안 약간의 코드 부풀림이 발생합니다. 일반적으로 이것은 문제가되지 않지만, 거의 항상 Compact Framework 세계에서는 엄격한 메모리 제약에 맞서기 때문에 이와 같은 작은 절약도 중요합니다.


4

사용을 피해서는 안되지만 다른 기여자가 제공 한 이유로 자격과주의를 기울여 사용해야합니다.

나는 내부적으로 데이터베이스에 대한 out-of-process 호출을 열고 고객 목록을 읽는 Customers와 같은 속성을 본 적이 있습니다. 클라이언트 코드에는 'for (int i to Customers.Count)'가있어서 반복 할 때마다 그리고 선택한 고객의 액세스를 위해 데이터베이스에 대한 별도의 호출이 발생했습니다. 이것은 재산을 매우 가볍게 유지하는 원칙을 보여주는 끔찍한 예입니다.

속성 사용에 대한 한 가지 인수는 설정되는 값의 유효성을 검사 할 수 있다는 것입니다. 다른 하나는 속성 값이 TotalValue = amount * quantity와 같이 단일 필드가 아닌 파생 값일 수 있다는 것입니다.


3

개인적으로 간단한 get / set 메서드를 만들 때만 속성을 사용합니다. 나는 복잡한 데이터 구조에 다가올 때 그것을 벗어났습니다.


3

이 인수는 속성이 필드처럼 보이기 때문에 나쁘다고 가정하지만 놀라운 작업을 수행 할 수 있습니다. 이 가정은 .NET 프로그래머의 기대에 의해 무효화됩니다.

속성은 필드처럼 보이지 않습니다. 필드는 속성처럼 보입니다.

• 속성 메서드에서 예외가 발생할 수 있습니다. 필드 액세스는 예외를 발생시키지 않습니다.

따라서 필드는 예외를 throw하지 않는 속성과 같습니다.

• 속성은 out 또는 ref 매개 변수로 메서드에 전달할 수 없습니다. 필드는 할 수 있습니다.

따라서 필드는 속성과 비슷하지만 메서드에 전달 ref/ out수락 하는 추가 기능이 있습니다.

• 속성 메서드를 실행하는 데 시간이 오래 걸릴 수 있습니다. 필드 액세스는 항상 즉시 완료됩니다. [...]

따라서 필드는 빠른 속성과 같습니다.

• 연속적으로 여러 번 호출되는 경우 속성 메서드는 매번 다른 값을 반환 할 수 있습니다. 필드는 매번 동일한 값을 반환합니다. System.DateTime 클래스에는 현재 날짜와 시간을 반환하는 readonly Now 속성이 있습니다.

따라서 필드는 필드가 다른 값으로 설정되지 않는 한 동일한 값을 반환하도록 보장되는 속성과 같습니다.

• 속성 방법은 관찰 가능한 부작용을 일으킬 수 있습니다. 필드 액세스는 절대하지 않습니다.

다시 말하지만 필드는 그렇게하지 않는 것이 보장되는 속성입니다.

• 속성 메서드에는 추가 메모리가 필요하거나 실제로 객체 상태의 일부가 아닌 항목에 대한 참조를 반환 할 수 있으므로 반환 된 객체를 수정해도 원래 객체에는 영향을주지 않습니다. 필드를 쿼리하면 항상 원래 개체 상태의 일부가 보장되는 개체에 대한 참조가 반환됩니다. 복사본을 반환하는 속성으로 작업하는 것은 개발자에게 매우 혼란 스러울 수 있으며이 특성은 종종 문서화되지 않습니다.

이것은 놀랍지 만 이것을 수행하는 속성이기 때문에 아닙니다. 오히려 속성에서 가변 복사본을 반환하는 사람이 거의 없기 때문에 0.1 %의 경우는 놀랍습니다.


0

속성 대신 메서드를 호출하면 호출 코드의 가독성이 크게 저하됩니다. 예를 들어 J #에서 ADO.NET을 사용하는 것은 Java가 속성 및 인덱서 (기본적으로 인수가있는 속성)를 지원하지 않기 때문에 악몽이었습니다. 결과 코드는 빈 괄호 메서드 호출이 모든 곳에서 매우 추악했습니다.

속성 및 인덱서에 대한 지원은 Java에 비해 C #의 기본 이점 중 하나입니다.

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