Dlaczego nie zaleca się posiadania właściwości tylko do ustawiania?


9

Dzisiaj w pracy jeden z moich kolegów przejrzał mój kod i zasugerował, żebym usunął właściwość tylko do zestawu i zamiast tego użyłem metody.

Ponieważ oboje byliśmy zajęci innymi rzeczami, powiedział mi, abym przejrzał Property Designsekcję z książki „Wytyczne projektowania ramowego”. W książce pisarz powiedział właśnie, aby unikać:

Właściwości, w których seter ma szerszą dostępność niż getter

A teraz zastanawiam się, dlaczego nie zaleca się posiadania właściwości tylko do ustawiania? Czy ktoś może mi wyjaśnić?


6
Czy możesz opisać sytuację, w której uważasz, że właściwość tylko do zestawu jest odpowiednia? Może to uczynić odpowiedzi nieco bardziej trafnymi.
JohnFx

1
Próbuję wymyślić przykład, który ma sens semantyczny. Jedyne, co przychodzi na myśl, to Passwordwłasność w Userklasie. Możesz to ustawić, ale nie możesz tego zdobyć. Możesz wtedy mieć HashedPasswordwłaściwość tylko do odczytu . Wywołanie zestawu spowoduje wykonanie skrótu i ​​zmianę HashedPasswordwłaściwości. Nie krzyczałbym na ciebie, gdybyś to zrobił.
Scott Whitlock,

Odpowiedzi:


15

Myślę, że może to mieć związek z oczekiwaniami. Właściwości tylko zestawu są rzadkie, a właściwości są zwykle używane w „głupich” zestawach tylko do przechowywania wartości bez większego przetwarzania. Jeśli wykonujesz dużo pracy w seterach, lepiej jest użyć metody - ludzie oczekują, że metody mogą potrwać długo i mogą mieć skutki uboczne. Implementacja podobnego rodzaju zachowania we właściwości może spowodować, że kod narusza oczekiwania.

Oto odpowiednia sekcja Wytycznych użytkowania nieruchomości Microsoft :

Właściwości a metody

Projektanci bibliotek klas często muszą decydować o zaimplementowaniu elementu klasy jako właściwości lub metody. Ogólnie metody reprezentują działania, a właściwości reprezentują dane. Skorzystaj z poniższych wskazówek, aby wybrać jedną z tych opcji.

  • Użyj właściwości, gdy członek jest logicznym członkiem danych. W poniższych deklaracjach członkowskich Namejest właściwością, ponieważ jest logicznym członkiem klasy.
public string Name
{
    get 
    {
        return name;
    }
    set 
    {
        name = value;
    }
}

Użyj metody, gdy:

  • Operacja jest konwersją, taką jak Object.ToString.
  • Operacja jest na tyle kosztowna, że ​​użytkownik chce poinformować użytkownika, że ​​powinien rozważyć zapisanie wyniku w pamięci podręcznej.
  • Uzyskanie wartości właściwości za pomocą getakcesorium miałoby zauważalny efekt uboczny.
  • Dwukrotne dzwonienie do członka daje różne wyniki.
  • Kolejność wykonania jest ważna. Pamiętaj, że właściwości typu powinny być ustawione i wyszukiwane w dowolnej kolejności.
  • Element jest statyczny, ale zwraca wartość, którą można zmienić.
  • Członek zwraca tablicę. Właściwości zwracające tablice mogą być bardzo mylące. Zwykle konieczne jest zwrócenie kopii tablicy wewnętrznej, aby użytkownik nie mógł zmienić stanu wewnętrznego. To w połączeniu z faktem, że użytkownik może łatwo założyć, że jest to właściwość indeksowana, prowadzi do nieefektywnego kodu. W poniższym przykładzie kodu każde wywołanie właściwości Methods tworzy kopię tablicy. W rezultacie 2 ^ n + 1 kopii tablicy zostaną utworzone w następnej pętli.
Type type = // Get a type.
for (int i = 0; i < type.Methods.Length; i++)
{
   if (type.Methods[i].Name.Equals ("text"))
   {
      // Perform some operation.
   }
}

[... pominął dłuższy przykład ...]

Właściwości tylko do odczytu i tylko do zapisu

Należy użyć właściwości tylko do odczytu, gdy użytkownik nie może zmienić elementu danych logicznych właściwości. Nie używaj właściwości tylko do zapisu.


Tak - tutaj obowiązuje zasada najmniejszego zaskoczenia.
Paul Butcher

6

Ponieważ w większości przypadków nie ma to po prostu sensu. Jaką możesz mieć właściwość, którą możesz ustawić, ale nie możesz odczytać?

Jeśli OO ma lepiej reprezentować rzeczywisty świat, właściwość tylko zestaw może sugerować, że twoje modelowanie jest całkiem niezłe.

Edycja : Zobacz także: /programming/4564928/are-set-only-properties-bad-practice, który zasadniczo mówi, że jest nieintuicyjny, a właściwość only set jest w zasadzie metodą o innej nazwie, więc powinieneś użyć metoda.


1
Wcześniej korzystałem z właściwości tylko zestawu. Piszą do prywatnego pola obiektu, aby skonfigurować jego zachowanie. Są przydatne, gdy zewnętrzny kod nie musi znać bieżącej wartości, ale może wymagać jej zmiany. To oczywiście rzadkie, ale widziałem, jak to się dzieje.
Mason Wheeler

@Mason - Na pewno nigdy nie posunę się tak daleko do stwierdzenia, że nigdy nie powinieneś ich używać, ale zasadniczo powinny one stanowić raczej wyjątek niż regułę.
Jon Hopkins

@MasonWheeler nie jest to w przybliżeniu Foo Foo { private get; set; }? Nie nazwałbym tego tylko
pisaniem

6

Cóż, wyobrażam sobie, że jeśli możesz ustawić właściwość na czymś, ale nigdy jej nie uzyskasz, nigdy nie dowiesz się, czy coś innego zmieni / nadpisze ustawioną wartość. Może to stanowić problem, jeśli polegasz na ustawionej wartości i nie jesteś w stanie (z jakiegoś powodu) utrzymać jej do czasu, w którym chcesz ją uzyskać.

Użycie metody zamiast właściwości tylko dla zestawu będzie nieco mniej mylące dla użytkownika. Nazwa metody zwykle wskazuje SEt- lub korzystać z telefonu , ale nazwy właściwości zwykle nie wskazują, że coś może tylko być ustawiony i nie można zdobyć. Podejrzewam, że gdyby właściwość była podobna do „ReadOnlyBackgroundColour”, nie byłoby to mylące dla innych programistów, ale wyglądałoby to dziwnie.


Zgadzam się, ale w jaki sposób metoda ustawiająca byłaby inna w tym przypadku?
Travis Christian

1
@Travis Christian: Wygląda na to, że OP działa w sytuacji, w której jest rozgrywający, ale nie ma gettera. Więc mogą coś ustawić, ale nigdy się nie dowiedzą, czy to się zmieni później.
FrustratedWithFormsDesigner

@Frustrated Ale oni też nigdy nie będą wiedzieć, czy coś się zmieniło za pomocą metody.
Adam Lear

@Anna Lear ♦: Jeśli istnieje getter, możesz przynajmniej przetestować wartość przed użyciem, jeśli masz punkt w kodzie, w którym ustawiona wartość może nagle ulec wątpliwości.
FrustratedWithFormsDesigner

3
@ Sfrustrowany Zgadzam się. Tyle, że pytanie dotyczyło użycia właściwości tylko zestawu, a nie metody, aby zrobić to samo.
Adam Lear

-1

Jest to bardzo stary temat, który jednak pojawił się w mojej opinii na tym późnym etapie i chciałbym skomentować, gdy próbuję uzasadnić właściwości tylko do zapisu ...

Mam zestaw ActiveReportklas, które są częścią strony internetowej, które są tworzone i uruchamiane w trybie postback po kilku wyborach użytkowników.

Kod VB wygląda mniej więcej tak:

  Public Class SomeReport
    Private greader As New GenericReporting.CommonReader("AStoredProcedure", 
                                      {New SqlParameter("budget_id", 0)})

    Public WriteOnly Property BudgetID As Integer
      Set(value As Integer)
        greader.Parameters("budget_id").Value = value
      End Set
    End Property

    Public Sub New(Optional budget_id As Integer = 0)
      ' This call is required by the designer.
      InitializeComponent()

      ' Add any initialization after the InitializeComponent() call.
      BudgetID = budget_id
    End Sub
  End Class

Te raporty używają ogólnych odwzorowań, CommonReaderbiorą procedurę składowaną i tablicę domyślnych SqlParameters, z których każdy ma powiązaną właściwość WriteOnly, która w zależności od projektu raportu może zostać przekazana jako parametr podczas tworzenia instancji lub ustawiona przez użytkownika po utworzeniu instancji przed wywołanie Runmetody raportów .

  '''''''''''''''''''''''
  ' Parameter taken from a user selected row of a GridView
  '
  Dim SomeBudgetID As Integer = gvBudgets.SelectedDataKey.Values(budget_id)

  '''''''''''''''''''''''      
  ' On Instantiation
  '
  Dim R as ActiveReport = New SomeReport(SomeBudgetID)
  R.Run()

  '''''''''''''''''''''''      
  ' Or On Instantiation using "With" syntax
  '
  Dim R as ActiveReport = New SomeReport() With {.BudgetID = SomeBudgetID}
  R.Run()

  '''''''''''''''''''''''
  ' Or After
  '
  Dim R as ActiveReport = New SomeReport()
  R.BudgetID = SomeBudgetID
  R.Run()

Tak więc, jak widzę, w tym przypadku ma właściwość tylko do zapisu

  1. Umożliwia silniejsze sprawdzanie typu, ponieważ SqlParameters są rodzajowe
  2. Dzięki większej elastyczności tworzenia raportu, raport może zostać utworzony natychmiast, jeśli wszystkie parametry będą dostępne lub dodane później, gdy staną się dostępne.
  3. Właściwości obsługują składnię „With” przy tworzeniu instancji
  4. Czy „getter” jest naprawdę konieczny, ponieważ parametry są znane użytkownikowi i nie są zmieniane w raporcie?
  5. Ponieważ SqlParameters są klasami, a nie pierwotnymi wartościami, WriteOnly Properties pozwala na prostszy interfejs do ustawiania parametrów

Więc to są moje myśli.

Czy zamiast tego mogę przekonwertować go na metodę? jasne, ale interfejs wydaje się ... mniej przyjemny

  R2.BudgetID = SomeBudgetID

przeciw

  R2.SetBudgetID(SomeBudgetID)
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.