Mam klasę z dwoma readonly int
polami. Są eksponowane jako właściwości:
public class Thing
{
private readonly int _foo, _bar;
/// <summary> I AM IMMUTABLE. </summary>
public Thing(int foo, int bar)
{
_foo = foo;
_bar = bar;
}
public int Foo { get { return _foo; } set { } }
public int Bar { get { return _bar; } set { } }
}
Oznacza to jednak, że następujący kod jest całkowicie zgodny z prawem:
Thing iThoughtThisWasMutable = new Thing(1, 42);
iThoughtThisWasMutable.Foo = 99; // <-- Poor, mistaken developer.
// He surely has bugs now. :-(
Błędy wynikające z założenia, że to zadziała, z pewnością będą podstępne. Jasne, błędny programista powinien przeczytać dokumenty. Ale to nie zmienia faktu, że żaden błąd kompilacji lub wykonania nie ostrzegł go o problemie.
Jak Thing
zmienić klasę, aby deweloperzy nie popełnili powyższego błędu?
Rzuć wyjątek? Używasz metody gettera zamiast właściwości?
c#
object-oriented
immutability
properties
kdbanman
źródło
źródło
Interfaces
. Nie jestem pewien, czy to właśnie robię.Odpowiedzi:
Dlaczego ten kodeks jest legalny?
Wyjmij,
set { }
jeśli nic nie robi.Oto jak definiujesz własność publiczną tylko do odczytu:
źródło
public int Foo { get; }
(auto-własność tylko z geterem) Alepublic int Foo { get; private set; }
jest.W wersji C # 5 i wcześniejszych mieliśmy do czynienia z dwiema opcjami dla niezmiennych pól eksponowanych przez getter:
readonly
aby zniszczyć niezmienność. Stworzyło to jednak mnóstwo kodu płyty kotłowej.Jednak w wersji C # 6 (dostępnej w wersji VS2015, która została wydana wczoraj), otrzymujemy to, co najlepsze z obu światów: właściwości automatyczne tylko do odczytu. To pozwala nam uprościć klasę OP w celu:
Foo = foo
IBar = bar
linie są ważne tylko w konstruktor (co osiąga się niezawodne wymagania tylko do odczytu), i pole podłoża zakłada się, zamiast być wyraźnie określone (który uzyskuje się prostszą kodu).źródło
Możesz po prostu pozbyć się seterów. Nic nie robią, wprowadzą użytkowników w błąd i doprowadzą do błędów. Możesz jednak zamiast tego ustawić je jako prywatne i pozbyć się zmiennych pomocniczych, upraszczając kod:
źródło
public int Foo { get; private set; }
” Ta klasa nie jest już niezmienna, ponieważ może się zmienić. W każdym razie dzięki!readonly
Kluczowe jest tylko Poka-Yoke, czyli chroni przed klasą zerwania immutablity w przyszłości; nie jest to jednak konieczne do osiągnięcia niezmienności.Dwa rozwiązania.
Prosty:
Nie dołączaj seterów, jak zauważył David dla niezmiennych obiektów tylko do odczytu.
Alternatywnie:
Zezwól ustawiającym na zwrócenie nowego niezmiennego obiektu, szczegółowego w porównaniu z poprzednim, ale zapewnia stan w czasie dla każdego zainicjowanego obiektu. Ta konstrukcja jest bardzo przydatnym narzędziem do zapewnienia bezpieczeństwa i niezmienności wątków, które obejmuje wszystkie niezbędne języki OOP.
Pseudo kod
publiczna fabryka statyczna
źródło