Dlaczego należy unikać używania właściwości w języku C #?

102

W swojej znakomitej książce „CLR Via C #” Jeffrey Richter powiedział, że nie lubi właściwości i odradza ich używanie. Podał jakiś powód, ale tak naprawdę nie rozumiem. Czy ktoś może mi wyjaśnić, dlaczego powinienem lub nie powinienem używać właściwości? Czy w języku C # 3.0 z właściwościami automatycznymi to się zmienia?

Jako odniesienie dodałem opinie Jeffreya Richtera:

• Właściwość może być tylko do odczytu lub tylko do zapisu; dostęp do pól jest zawsze czytelny i zapisywalny. Jeśli definiujesz właściwość, najlepiej jest oferować metody dostępu zarówno get, jak i set.

• Metoda właściwości może zgłosić wyjątek; dostęp do pola nigdy nie zgłasza wyjątku.

• Właściwość nie może być przekazana jako parametr out lub ref do metody; pole może. Na przykład następujący kod nie zostanie skompilowany:

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);
   }
}

• Metoda właściwości może zająć dużo czasu; dostęp do pola zawsze kończy się natychmiast. Częstym powodem używania właściwości jest wykonanie synchronizacji wątków, która może zatrzymać wątek na zawsze, dlatego też właściwość nie powinna być używana, jeśli wymagana jest synchronizacja wątków. W takiej sytuacji preferowana jest metoda. Ponadto, jeśli do Twojej klasy można uzyskać dostęp zdalnie (na przykład Twoja klasa pochodzi z System.MashalByRefObject), wywołanie metody właściwości będzie bardzo powolne, a zatem metoda jest preferowana zamiast właściwości. Moim zdaniem klasy pochodzące od MarshalByRefObject nigdy nie powinny używać właściwości.

• Jeśli metoda właściwości zostanie wywołana wiele razy z rzędu, za każdym razem może zwrócić inną wartość; pole zwraca za każdym razem tę samą wartość. Klasa System.DateTime ma właściwość Readonly Now, która zwraca bieżącą datę i godzinę. Za każdym razem, gdy zapytasz o tę właściwość, zwróci ona inną wartość. To jest błąd i firma Microsoft życzy sobie, aby mogli naprawić klasę, tworząc metodę Now zamiast właściwości.

• Metoda właściwości może powodować obserwowalne skutki uboczne; dostęp do pola nigdy nie ma. Innymi słowy, użytkownik typu powinien mieć możliwość ustawiania różnych właściwości zdefiniowanych przez typ w dowolnej kolejności, bez zauważania innego zachowania w typie.

• Metoda właściwości może wymagać dodatkowej pamięci lub zwrócić odniesienie do czegoś, co w rzeczywistości nie jest częścią stanu obiektu, więc modyfikacja zwróconego obiektu nie ma wpływu na oryginalny obiekt; zapytanie o pole zawsze zwraca odwołanie do obiektu, który na pewno jest częścią stanu oryginalnego obiektu. Praca z właściwością, która zwraca kopię, może być bardzo myląca dla programistów, a ta cecha często nie jest udokumentowana.

Quan Mai
źródło
11
Jestem właścicielem trzeciego wydania „CLR via C #” i na stronie 242 pan Richter mówi, że osobiście nie lubi nieruchomości, ale nigdy nie zaleca ich używania. Proszę podać wersję książki i numer strony, na której to czytałeś.
kirk.burleson

Odpowiedzi:

173

Jeff nie lubi właściwości, ponieważ wyglądają jak pola - więc programiści, którzy nie rozumieją różnicy, będą traktować je tak, jakby były polami, zakładając, że będą tanie w wykonaniu itp.

Osobiście nie zgadzam się z nim w tym konkretnym punkcie - uważam, że właściwości sprawiają, że kod klienta jest znacznie prostszy do odczytania niż równoważne wywołania metod. Zgadzam się, że programiści muszą wiedzieć, że właściwości są w zasadzie metodami zamaskowanymi - ale myślę, że edukacja programistów na ten temat jest lepsza niż utrudnianie czytania kodu za pomocą metod. (W szczególności, widząc kod Javy z kilkoma metodami pobierającymi i ustawiającymi wywoływanymi w tej samej instrukcji, wiem, że równoważny kod C # byłby o wiele prostszy do odczytania. Prawo Demeter jest bardzo dobre w teorii, ale czasami foo.Name.Lengthtak naprawdę jest właściwa rzecz do użycia ...)

(I nie, automatycznie implementowane właściwości tak naprawdę niczego nie zmieniają).

Jest to trochę podobne do argumentów przeciwko stosowaniu metod rozszerzających - rozumiem rozumowanie, ale praktyczna korzyść (gdy jest używana oszczędnie) przeważa w moim przekonaniu.

Jon Skeet
źródło
Bardzo dziękuję za odpowiedź! O argumentach przeciwko używaniu metod rozszerzających: czy mówisz o jakimś temacie Jeffreya Richtera, czy też w skrócie?
abatishchev
@abatishchev: To był tylko ogólny punkt dotyczący metod rozszerzających. Nie jest bezpośrednio związane z właściwościami.
Jon Skeet
Poszedłbym dalej. Z wyjątkiem aspektu wydajnościowego nie rozumiem, dlaczego programista miałby WIEDZIEĆ, czy coś jest polem, czy właściwością. Powinien myśleć o tym jako o atrybucie instancji wyznaczającym STAN instancji obiektu, a implementacja obiektu powinna dbać o wszystkie modyfikacje jego stanu (w ramach kontraktu klasy). Zatem właściwości mogą równie dobrze być polami w niektórych przypadkach lub stać się polami w innych, jeśli być może zostanie przeprojektowana implementacja klasy. Wówczas decyzja między polem a dobrem jest kwestią tego, ile ochrony potrzebuje państwo, aby zachować spójność.
TheBlastOne
1
@PatrickFromberg: Najwyraźniej przegapiłeś dużą ilość kodu, który używa pól tylko do odczytu. Nie ma co mówić, że właściwości implikują zmienność. Często mam pola tylko do odczytu, które wspierają właściwości tylko do odczytu - czy uważasz, że to zła rzecz?
Jon Skeet,
1
@Patrick: Nie, to przynosi korzyść w postaci oddzielenia API od implementacji - możesz później zmienić sposób obliczania właściwości z pola (np. Aby obliczyć dwie powiązane właściwości z jednego pola).
Jon Skeet
34

Cóż, weźmy jego argumenty jeden po drugim:

Właściwość może być tylko do odczytu lub tylko do zapisu; dostęp do pól jest zawsze czytelny i zapisywalny.

Jest to korzystne dla nieruchomości, ponieważ masz bardziej szczegółową kontrolę dostępu.

Metoda właściwości może zgłosić wyjątek; dostęp do pola nigdy nie zgłasza wyjątku.

Chociaż jest to w większości prawda, bardzo dobrze można wywołać metodę na niezainicjowanym polu obiektu i zgłosić wyjątek.

• Właściwość nie może być przekazana jako parametr out lub ref do metody; pole może.

Targi.

• Metoda właściwości może zająć dużo czasu; dostęp do pola zawsze kończy się natychmiast.

Może to również zająć bardzo mało czasu.

• Jeśli metoda właściwości zostanie wywołana wiele razy z rzędu, za każdym razem może zwrócić inną wartość; pole zwraca za każdym razem tę samą wartość.

Nie prawda. Skąd wiesz, że wartość pola nie zmieniła się (prawdopodobnie przez inny wątek)?

Klasa System.DateTime ma właściwość Readonly Now, która zwraca bieżącą datę i godzinę. Za każdym razem, gdy zapytasz o tę właściwość, zwróci ona inną wartość. To jest błąd i firma Microsoft życzy sobie, aby mogli naprawić klasę, tworząc metodę Now zamiast właściwości.

Jeśli to pomyłka, to drobna.

• Metoda właściwości może powodować obserwowalne skutki uboczne; dostęp do pola nigdy nie ma. Innymi słowy, użytkownik typu powinien mieć możliwość ustawiania różnych właściwości zdefiniowanych przez typ w dowolnej kolejności, bez zauważania innego zachowania w typie.

Targi.

• Metoda właściwości może wymagać dodatkowej pamięci lub zwrócić odniesienie do czegoś, co w rzeczywistości nie jest częścią stanu obiektu, więc modyfikacja zwróconego obiektu nie ma wpływu na oryginalny obiekt; zapytanie o pole zawsze zwraca odwołanie do obiektu, który na pewno jest częścią stanu oryginalnego obiektu. Praca z właściwością, która zwraca kopię, może być bardzo myląca dla programistów, a ta cecha często nie jest udokumentowana.

Większość protestów można by powiedzieć także o getterach i seterach Javy - i mieliśmy je przez dłuższy czas bez takich problemów w praktyce.

Myślę, że większość problemów można by rozwiązać przez lepsze podświetlanie składni (tj. Różnicowanie właściwości z pól), aby programista wiedział, czego się spodziewać.

Hejazzman
źródło
3
„problemy można rozwiązać przez lepsze podświetlanie składni” : Jak często używasz pól publicznych? Pola prywatne mają zazwyczaj inny styl, np _field. Lub po prostu małe litery field.
Steven Jeuris
18

Nie czytałem tej książki, a ty nie zacytowałeś jej części, której nie rozumiesz, więc muszę zgadywać.

Niektórzy ludzie nie lubią właściwości, ponieważ mogą sprawić, że Twój kod będzie robił zaskakujące rzeczy.

Jeśli piszę Foo.Bar, osoby czytające zwykle będą oczekiwać, że jest to po prostu dostęp do pola członkowskiego klasy Foo. To tania, prawie bezpłatna operacja i jest deterministyczna. Mogę to powtarzać w kółko i za każdym razem uzyskuję ten sam wynik.

Zamiast tego, z właściwościami, może to być wywołanie funkcji. To może być nieskończona pętla. Może otworzyć połączenie z bazą danych. Może zwracać różne wartości za każdym razem, gdy mam do niego dostęp.

Jest to podobny argument do tego, dlaczego Linus nienawidzi C ++. Twój kod może zaskoczyć czytelnika. Nienawidzi przeciążania operatorów: a + bniekoniecznie oznacza proste dodawanie. Może to oznaczać bardzo skomplikowaną operację, podobnie jak właściwości C #. Może mieć skutki uboczne. To może zrobić wszystko.

Szczerze mówiąc, uważam, że to słaby argument. Oba języki są pełne takich rzeczy. (Czy powinniśmy unikać przeciążania operatorów również w C #? W końcu można tam użyć tego samego argumentu)

Właściwości pozwalają na abstrakcję. Możemy udawać, że coś jest zwykłym polem i używać go tak, jakby nim było, i nie martwić się o to, co dzieje się za kulisami.

Zwykle uważa się to za dobrą rzecz, ale oczywiście polega na pisaniu przez programistę znaczących abstrakcji. Twoje właściwości powinny zachowywać się jak pola. Nie powinny mieć skutków ubocznych, nie powinny wykonywać drogich lub niebezpiecznych operacji. Chcemy myśleć o nich jak o polach.

Mam jednak inny powód, by uważać je za mniej niż doskonałe. Nie można ich przekazywać przez odwołanie do innych funkcji.

Pola można przekazywać jako ref, umożliwiając wywoływanej funkcji bezpośredni do nich dostęp. Funkcje można przekazywać jako delegatów, umożliwiając wywoływanej funkcji bezpośredni do nich dostęp.

Właściwości ... nie mogą.

To jest do bani.

Ale to nie znaczy, że właściwości są złe lub nie powinny być używane. Z wielu powodów są świetne.

jalf
źródło
3
Mój argument jest taki, że nie powinieneś zakładać, że jest to pole, od którego należy zacząć - ponieważ jeśli wywołujesz je z innej klasy, i tak nie powinieneś mieć dostępu do pól niestałych, ponieważ powinny być prywatne. (Jest też konwencja nazewnictwa, aby Cię poinformować.)
Jon Skeet,
1
Tak! Zgadzam się. Wydaje się, że argument sprowadza się do „Przyzwyczaiłem się do tego, że składnia jest używana wyłącznie dla pól. Dlatego rozszerzenie jej na inne przypadki jest złe”. I oczywista odpowiedź brzmi: „No cóż, przyzwyczaić się więc do innych spraw, a nie będzie źle”. ;)
jalf
Chciałbym, żeby języki .net zapewniały standardowe środki, za pomocą których klasa ujawnia właściwości jako parametry ref; element członkowski (np. Foo) formularza void Foo<T>(ActionByRef<Point,T> proc, ref T param)ze specjalnym atrybutem, a kompilator przekształci go thing.Foo.X+=someVar;w Foo((ref Point it, ref int param)=>it.X += param, ref someVar);. Ponieważ lambda jest delegatem statycznym, nie będzie wymagane żadne zamknięcie, a użytkownik obiektu będzie mógł użyć dowolnej lokalizacji magazynu, dla której właściwość jest obsługiwana jako prawdziwy refparametr (i może przekazać ją do innych metod jako refparametr).
supercat
Ręczne wypisanie lambdy daje naprawdę obrzydliwie wyglądający kod źródłowy, ale dlatego pomocny byłby kompilator wykonujący transformację. Kod klasy ujawniający właściwość „callback-by-ref” byłby całkiem rozsądny. Kod jest jedyny brzydki (bez transformacji) po stronie wywołującego.
supercat
Proszę zrozumieć, że właściwość jest wywołaniem funkcji zamaskowanym jako element członkowski, więc nie można jej przekazać przez odwołanie, tak samo jak nie można przekazać funkcji publicznych klasy. Zawsze możesz skorzystać z publicznego członka, jeśli zamierzasz to zrobić w ten sposób. Właściwość jest inteligentnym składnikiem, może zgłosić wyjątek dla nieprawidłowych danych przekazanych do zestawu.
Diceyus
17

W 2009 roku ta rada wydawała się po prostu przekleństwem odmiany Who Moved My Cheese . Dziś jest prawie śmiesznie przestarzały.

Jedną z bardzo ważnych kwestii, na którą wiele odpowiedzi wydaje się chodzić na palcach, ale nie do końca się do nich odnosi, jest to, że te rzekome „niebezpieczeństwa” związane z właściwościami są celową częścią projektu struktury!

Tak, nieruchomości mogą:

  • Określ różne modyfikatory dostępu dla metody pobierającej i ustawiającej. To przewaga nad polami. Powszechnym wzorcem jest posiadanie publicznego pobierającego i chronionego lub wewnętrznego ustawiacza, bardzo użytecznej techniki dziedziczenia, której nie można osiągnąć za pomocą samych pól.

  • Podaj wyjątek. Do tej pory jest to jedna z najskuteczniejszych metod walidacji, zwłaszcza podczas pracy ze strukturami interfejsu użytkownika, które obejmują koncepcje powiązań danych. O wiele trudniej jest zapewnić, że obiekt pozostanie w prawidłowym stanie podczas pracy z polami.

  • Wykonanie zajmie dużo czasu. Prawidłowe porównanie dotyczy metod , które zajmują równie dużo czasu - nie pól . Nie podano żadnej innej podstawy dla stwierdzenia „preferowana jest metoda” niż osobiste preferencje jednego autora.

  • Zwraca różne wartości z jego metody pobierającej w kolejnych wykonaniach. Wydaje się to prawie żartem w tak bliskiej odległości od punktu wychwalającego zalety ref/ outparametry z polami, których wartość pola po a ref/out wywołaniu jest prawie gwarantowana, że ​​różni się od poprzedniej wartości, i to w sposób nieprzewidywalny.

    Jeśli mówimy o konkretnym (i praktycznie akademickim) przypadku dostępu jednowątkowego bez połączeń doprowadzających, to jest całkiem dobrze zrozumiałe, że to po prostu zły projekt właściwości, aby mieć efekty uboczne zmieniające stan widzialny, a może moja pamięć jest zanikają, ale nie mogę sobie przypomnieć żadnych przykładów ludzi używających DateTime.Nowi oczekujących, że za każdym razem wyjdzie ta sama wartość. Przynajmniej nie ma żadnych przypadków, w których nie schrzaniliby tego tak samo źle z hipotetą DateTime.Now().

  • Wywołuj obserwowalne skutki uboczne - i to jest właśnie powód, dla którego właściwości zostały wymyślone przede wszystkim jako cecha języka. Wytyczne firmy Microsoft dotyczące projektowania właściwości wskazują, że kolejność ustawiaczy nie powinna mieć znaczenia, ponieważ w przeciwnym razie oznaczałoby to czasowe sprzężenie . Z pewnością nie można osiągnąć czasowego sprzężenia z samymi polami, ale to tylko dlatego, że nie można w ogóle spowodować żadnego znaczącego zachowania z samymi polami, dopóki nie zostanie wykonana jakaś metoda.

    Metody dostępu do właściwości mogą w rzeczywistości pomóc w zapobieganiu niektórym typom sprzężeń czasowych przez wymuszenie na obiekcie prawidłowego stanu przed podjęciem jakiejkolwiek akcji - na przykład, jeśli klasa ma a StartDatei an EndDate, wówczas ustawienie EndDateprzed StartDatemoże również wymusić StartDatecofnięcie. Dzieje się tak nawet w środowiskach wielowątkowych lub asynchronicznych, w tym w oczywistym przykładzie interfejsu użytkownika sterowanego zdarzeniami.

Inne rzeczy, które mogą robić właściwości, których pola nie mogą obejmować:

  • Ładowanie z opóźnieniem , jeden z najskuteczniejszych sposobów zapobiegania błędom kolejności inicjalizacji.
  • Powiadomienia o zmianach , które są prawie całą podstawą architektury MVVM .
  • Dziedziczenie , na przykład definiowanie klas abstrakcyjnych Typelub innych Nameklas pochodnych, może dostarczyć interesujących, ale jednak stałych metadanych o sobie.
  • Przechwytywanie dzięki powyższemu.
  • Indeksatory , które każdy, kto kiedykolwiek miał do czynienia z interopem COM i nieuniknionym wyrzucaniem Item(i)połączeń, uzna za cudowną rzecz.
  • Pracuj z PropertyDescriptor, który jest niezbędny do tworzenia projektantów i ogólnie dla struktur XAML.

Richter jest wyraźnie płodnym autorem i wie dużo o CLR i C #, ale muszę powiedzieć, że wydaje się, że kiedy pierwotnie napisał tę poradę (nie jestem pewien, czy jest to w jego nowszych wersjach - mam szczerą nadzieję, że nie) że po prostu nie chciał porzucić starych nawyków i miał problemy z zaakceptowaniem konwencji C # (na przykład w porównaniu z C ++).

Rozumiem przez to, że jego argument o „właściwościach uważanych za szkodliwe” sprowadza się zasadniczo do jednego stwierdzenia: właściwości wyglądają jak pola, ale mogą nie działać jak pola. Problem z tym stwierdzeniem polega na tym, że nie jest ono prawdą lub w najlepszym przypadku jest bardzo mylące. Właściwości nie wyglądają jak pola - przynajmniej nie powinny wyglądać jak pola.

Istnieją dwie bardzo mocne konwencje kodowania w C # z podobnymi konwencjami wspólnymi dla innych języków CLR, a FXCop będzie na ciebie krzyczeć, jeśli ich nie będziesz przestrzegać:

  1. Pola powinny być zawsze prywatne, nigdy publiczne.
  2. Pola należy zadeklarować w camelCase. Właściwości to PascalCase.

W związku z tym nie ma niejednoznaczności co do tego, czy Foo.Bar = 42jest to metoda dostępu do właściwości, czy do pola. Jest to metoda dostępu do właściwości i powinna być traktowana jak każda inna metoda - może być powolna, może zgłosić wyjątek, itp. Taka jest natura abstrakcji - to całkowicie zależy od klasy deklarującej, jak zareagować. Projektanci klas powinni stosować zasadę najmniejszego zaskoczenia, ale dzwoniący nie powinni niczego zakładać na temat nieruchomości poza tym, że robi to, co mówi na puszce. To jest celowe.

Alternatywą dla właściwości są wszędzie metody pobierające / ustawiające. Takie jest podejście Java i od samego początku było kontrowersyjne . W porządku, jeśli to twoja torba, ale po prostu tak nie jest w obozie .NET. Próbujemy, przynajmniej w ramach systemu statycznego, unikać tego, co Fowler nazywa szumem syntaktycznym . Nie chcemy dodatkowych nawiasów, dodatkowych get/ setbrodawek ani dodatkowych sygnatur metod - nie, jeśli możemy ich uniknąć bez utraty przejrzystości.

Powiedz, co chcesz, ale foo.Bar.Baz = quux.Answers[42]zawsze będzie to o wiele łatwiejsze do przeczytania niż foo.getBar().setBaz(quux.getAnswers().getItem(42)). A kiedy czytasz tysiące linijek tego dnia, to robi różnicę.

(A jeśli twoją naturalną odpowiedzią na powyższy akapit jest powiedzenie „z pewnością trudno go przeczytać, ale byłoby łatwiej, gdybyś podzielił to na wiele wierszy”, to przykro mi, że całkowicie przegapiłeś ten punkt .)

Aaronaught
źródło
11

Nie widzę żadnych powodów, dla których ogólnie nie powinieneś używać Właściwości.

Automatyczne właściwości w C # 3+ tylko trochę upraszczają składnię (a la syntatic sugar).

Konstantin Tarkus
źródło
przeczytaj w tej książce strony 215-216. Jestem pewien, że wiesz, kim jest Jeffrey Richter!
Quan Mai
Przeczytałem (CLR przez C #, wyd. 2), nie zgadzam się z jego stanowiskiem i nie widzę prawdziwych powodów, aby nie używać właściwości!
abatishchev
To dobra książka, ale w tej chwili nie zgadzam się z autorem.
Konstantin Tarkus
Gdzie dokładnie jest to miejsce, w którym autor sugeruje, aby nie używać Właściwości? Nie znalazłem nic na s. 215-217
Konstantin Tarkus
Dodałem opinie Jeffreya w moim pytaniu :). Można go znaleźć na stronach 215-216 w wersji drukowanej :)
Quan Mai
9

To tylko opinia jednej osoby. Przeczytałem sporo książek w języku C # i nie widziałem jeszcze nikogo mówiącego „nie używaj właściwości”.

Osobiście uważam, że właściwości są jedną z najlepszych rzeczy w języku C #. Pozwalają ci ujawnić stan za pomocą dowolnego mechanizmu. Możesz leniwie utworzyć instancję, gdy coś jest używane po raz pierwszy, i możesz przeprowadzić walidację ustawiania wartości itp. Używając ich i pisząc, myślę o właściwościach jako o ustawieniach i pobierających, co jest o wiele ładniejszą składnią.

Jeśli chodzi o zastrzeżenia dotyczące właściwości, jest kilka. Jeden jest prawdopodobnie niewłaściwym wykorzystaniem właściwości, drugi może być subtelny.

Po pierwsze, właściwości to rodzaje metod. Może być zaskakujące, jeśli umieścisz skomplikowaną logikę we właściwości, ponieważ większość użytkowników klasy będzie oczekiwać, że właściwość będzie dość lekka.

Na przykład

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(); }
   }
}

Uważam, że stosowanie metod w tych przypadkach pomaga dokonać rozróżnienia.

Po drugie, co ważniejsze, właściwości mogą mieć skutki uboczne, jeśli ocenisz je podczas debugowania.

Załóżmy, że masz taką nieruchomość:

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

Teraz załóżmy, że masz wyjątek, który występuje, gdy wykonano zbyt wiele zapytań. Zgadnij, co się dzieje, gdy zaczynasz debugowanie i przenoszenie właściwości w debugerze? Złe rzeczy. Unikaj tego! Spojrzenie na nieruchomość zmienia stan programu.

To są jedyne zastrzeżenia, jakie mam. Myślę, że zalety nieruchomości znacznie przewyższają problemy.

Mark Simpson
źródło
6

Powód ten musiał zostać podany w bardzo konkretnym kontekście. Zwykle jest na odwrót - zaleca się używanie właściwości, ponieważ zapewniają one poziom abstrakcji umożliwiający zmianę zachowania klasy bez wpływu na jej klientów ...

Rashack
źródło
+1 za niejawne podkreślenie znaczenia „kontraktu” między klientem a własnością klasy.
TheBlastOne
6

Nie mogę się powstrzymać od drążenia szczegółów opinii Jeffreya Richtera:

Właściwość może być tylko do odczytu lub tylko do zapisu; dostęp do pól jest zawsze czytelny i zapisywalny.

Źle: Pola mogą być oznaczone jako tylko do odczytu, więc tylko konstruktor obiektu może do nich pisać.

Metoda właściwości może zgłosić wyjątek; dostęp do pola nigdy nie zgłasza wyjątku.

Błąd: implementacja klasy może zmienić modyfikator dostępu pola z publicznego na prywatny. Próby odczytania pól prywatnych w czasie wykonywania zawsze kończą się wyjątkiem.

Cecil ma imię
źródło
5

Nie zgadzam się z Jeffreyem Richterem, ale domyślam się, dlaczego nie lubi nieruchomości (nie czytałem jego książki).

Chociaż właściwości są jak metody (pod względem implementacji), jako użytkownik klasy spodziewam się, że jej właściwości zachowują się „mniej więcej” jak pole publiczne, np .:

  • nie ma czasochłonnej operacji wykonywanej wewnątrz metody pobierającej / ustawiającej właściwości
  • właściwość getter nie ma skutków ubocznych (wywoływanie jej wielokrotnie, nie zmienia wyniku)

Niestety, widziałem nieruchomości, które nie zachowywały się w ten sposób. Ale problemem nie są same nieruchomości, ale ludzie, którzy je wdrożyli. Więc to wymaga tylko trochę edukacji.

M4N
źródło
1
+1, ponieważ podkreśla znaczenie czystej umowy. Posiadanie pozornej właściwości tylko do odczytu, która regularnie zwraca inną wartość w każdym odwołaniu, jest właściwością readwrite - po prostu nie zapisuje własnej wartości, ale inne zmienne instancji (bezpośrednio lub pośrednio). To nie jest zły styl, ale musi być udokumentowany (lub stanowić niejawną część umowy).
TheBlastOne
4

Jest czas, kiedy rozważam użycie właściwości, a jest to pisanie kodu .Net Compact Framework. Kompilator CF JIT nie wykonuje takiej samej optymalizacji, jak kompilator JIT dla komputerów stacjonarnych i nie optymalizuje prostych metod dostępu do właściwości, więc w tym przypadku dodanie prostej właściwości powoduje niewielkie rozdęcie kodu przy użyciu pola publicznego. Zwykle nie stanowiłoby to problemu, ale prawie zawsze w świecie Compact Framework masz do czynienia z ciasnymi ograniczeniami pamięci, więc nawet małe oszczędności takie jak ta mają znaczenie.

Steve
źródło
4

Nie powinieneś unikać ich używania, ale powinieneś używać ich z kwalifikacjami i ostrożnością, z powodów podanych przez innych współpracowników.

Kiedyś zobaczyłem właściwość o nazwie coś w rodzaju Klienci, która wewnętrznie otworzyła połączenie poza procesem do bazy danych i przeczytała listę klientów. Kod klienta miał „for (int i to Customers.Count)”, co powodowało oddzielne wywołanie bazy danych w każdej iteracji i dla dostępu wybranego Klienta. To skandaliczny przykład, który demonstruje zasadę utrzymywania nieruchomości w bardzo lekkim świetle - rzadko więcej niż dostęp do wewnętrznego pola.

Jednym z argumentów dla używania właściwości jest to, że pozwalają one na walidację ustawianej wartości. Innym jest to, że wartość właściwości może być wartością pochodną, ​​a nie pojedynczym polem, na przykład TotalValue = kwota * ilość.

Rob Kent
źródło
3

Osobiście używam właściwości tylko podczas tworzenia prostych metod get / set. Odchodzę od tego, dochodząc do skomplikowanych struktur danych.

Steve
źródło
3

Argument zakłada, że ​​właściwości są złe, ponieważ wyglądają jak pola, ale mogą wykonywać zaskakujące działania. To założenie jest obalone przez oczekiwania programistów .NET:

Właściwości nie wyglądają jak pola. Pola wyglądają jak właściwości.

• Metoda właściwości może zgłosić wyjątek; dostęp do pola nigdy nie zgłasza wyjątku.

Zatem pole jest jak właściwość, która gwarantuje, że nigdy nie zgłosi wyjątku.

• Właściwość nie może być przekazana jako parametr out lub ref do metody; pole może.

Zatem pole jest jak właściwość, ale ma dodatkowe możliwości: przechodzenie do ref/ outaccept metody.

• Metoda właściwości może zająć dużo czasu; dostęp do pola zawsze kończy się natychmiast. […]

Zatem pole jest jak szybka właściwość.

• Jeśli metoda właściwości zostanie wywołana wiele razy z rzędu, za każdym razem może zwrócić inną wartość; pole zwraca za każdym razem tę samą wartość. Klasa System.DateTime ma właściwość Readonly Now, która zwraca bieżącą datę i godzinę.

Zatem pole jest jak właściwość, która gwarantuje zwrócenie tej samej wartości, chyba że pole zostało ustawione na inną wartość.

• Metoda właściwości może powodować obserwowalne skutki uboczne; dostęp do pola nigdy nie ma.

Ponownie, pole jest właściwością, która na pewno tego nie robi.

• Metoda właściwości może wymagać dodatkowej pamięci lub zwrócić odniesienie do czegoś, co w rzeczywistości nie jest częścią stanu obiektu, więc modyfikacja zwróconego obiektu nie ma wpływu na oryginalny obiekt; zapytanie o pole zawsze zwraca odwołanie do obiektu, który na pewno jest częścią stanu oryginalnego obiektu. Praca z właściwością, która zwraca kopię, może być bardzo myląca dla programistów, a ta cecha często nie jest udokumentowana.

To może być zaskakujące, ale nie dlatego, że jest to właściwość, która to robi. Chodzi raczej o to, że prawie nikt nie zwraca mutowalnych kopii we właściwościach, więc wielkość 0,1% jest zaskakująca.

milleniumbug
źródło
0

Wywoływanie metod zamiast właściwości znacznie zmniejsza czytelność wywołującego kodu. Na przykład w J # używanie ADO.NET było koszmarem, ponieważ Java nie obsługuje właściwości i indeksatorów (które są zasadniczo właściwościami z argumentami). Wynikowy kod był wyjątkowo brzydki, z pustymi wywołaniami metody nawiasów w każdym miejscu.

Obsługa właściwości i indeksatorów jest jedną z podstawowych zalet języka C # w porównaniu z Javą.

Marty Solomon
źródło