2010-01-26 15 views
10

Jestem na projekcie ASP.Net 2.0, w języku C#. Mam niektóre dane, które zostaną zapisane w stanie sesji. Dla ułatwienia użytkowania jest on zawijany w następujący sposób:Czy ustawiacze właściwości .Net są kiedykolwiek wywoływane niejawnie?

protected IList<Stuff> RelevantSessionData 
{ 
    get 
    { 
     return (IList<Stuff>) Session["relevant_key"]; 
    } 
    set 
    { 
     Session["relevant_key"] = value; 
    } 
} 

Uzyskiwanie i ustawianie wartości działa dokładnie tak, jak można się spodziewać. Jeśli chcę wyczyścić wartość, po prostu ustawię ją na wartość null i nie ma problemów. Jednak na innej stronie programisty wywołuje metodę Clear() kolekcji. Myślałem, że to będzie błąd, ale wygląda na to, że działa i nie rozumiem dlaczego. Działa to tak:

Debug.WriteLine(RelevantSessionData.Count); //outputs, say, 3 
RelevantSessionData.Clear(); 
Debug.WriteLine(RelevantSessionData.Count); //outputs 0 

Dlaczego to działa? Moje naiwne oczekiwania polegałyby na tym, że środkowa linia ładuje serializowaną wartość z sesji, deserializuje się na obiekt, wywołuje Clear() na tym obiekcie, a następnie pozwala, aby nienazwany obiekt wypadł poza zasięg. Byłby to błąd, ponieważ wartość przechowywana w sesji pozostanie niezmieniona. Ale najwyraźniej jest wystarczająco inteligentny, aby wywołać funkcję ustawiania właściwości i ponownie przekształcić nowo zmienioną kolekcję z powrotem w sesję.

To mnie trochę denerwuje, ponieważ są miejsca w naszym starodawnym kodzie, w których seter nieruchomości ma efekty uboczne, i nie chcę, żeby ktoś dzwonił, jeśli nie jest przeznaczony.

Czy funkcja ustawiania właściwości jest zawsze wywoływana w takiej sytuacji? Czy coś się dzieje? Czy też zupełnie nie rozumiem, co się tutaj dzieje?

[Dodano wyjaśnienie odpowiedzi]
Okazuje się, że źle zrozumiałam. Wiedziałem, że obiekty przechowywane w Session muszą być przekształcalne do postaci szeregowej, i na tej podstawie stworzyłem zbyt wiele założeń dotyczących sposobu, w jaki kolekcja zachowuje się wewnętrznie. Zastanawiałem się.

Istnieje tylko jedno wystąpienie przechowywanego obiektu (mój IList). Każde wywołanie gettera zwraca odwołanie do tej samej instancji. Tak więc cytowany powyżej kod działa tak, jak się wydaje, bez specjalnej magii.

Aby odpowiedzieć na pytanie tytułowe: Nie, setery nie są wywoływane domyślnie.

Odpowiedz

4

Tak, masz rację, byłby to błąd, gdyby twój setter/getters serializował/deserializował obiekty. Ale tak nie jest. Zamiast tego przechodzisz na podstawie referencji.

Więc to, co się dzieje, to to, że pierwsza linijka w twoim przykładzie pobiera element za pomocą get, a na tej podstawie jest wywoływany Count. Następnie linia seccond wychodzi i wywołanie wraca ponownie, zwracając ten sam obiekt, działając czysto, a następnie trzecia linia robi to samo, co pierwsza.

Gdybyś napisał swoją setter/getter coś takiego, to masz „błąd”

protected IList<Stuff> RelevantSessionData 
{ 
    get 
    { 
     return (IList<Stuff>) JSON.ConvertFromString(Session["relevant_key"]); 
    } 
    set 
    { 
     Session["relevant_key"] = JSON.ConvertToString(value); 
    } 
} 

w tym przypadku nowy obiekt zostanie utworzony i dla każdego wywołania bloku GET. Ale ponieważ twój przykład powyżej po prostu omija odniesienie do tego samego obiektu, nie zobaczysz tego "błędu".

Mówię "błąd", ponieważ to nie jest błąd, to po prostu więcej nieporozumień co dzieje się za kulisami.

Mam nadzieję, że to pomoże.

+0

Aha! Przyjąłem, że ponieważ wartości w Session muszą być serializowalne, będą przechowywane w stanie szeregowym, a każde pobranie zwróci inne odwołanie. Jeśli tak nie jest i jest na tyle sprytny, aby zwracać to samo odwołanie w wielu rozmowach, to po prostu przemilczałem to. – Auraseer

1

Twój kod odpowiada w przybliżeniu:

Debug.WriteLine(((IList<Stuff>) Session["relevant_key"]).Count); //outputs, say, 3 
((IList<Stuff>) Session["relevant_key"]).Clear(); 
Debug.WriteLine(((IList<Stuff>) Session["relevant_key"]).Count); //outputs 0 

Nawet jeśli tylko wywołać getter, jesteś wyczyszczenie kolekcję. Tak więc wynik debugowania wydaje się normalny.

+5

+1. W rzeczywistości, najlepszą praktyką dla właściwości zbiorczych jest uczynienie ich tylko do odczytu (bez ustawiania). –

+0

Myślę, że przegapiłeś mój punkt widzenia. Wiem, co robi narzędzie dostępu, ale mój błąd polegał na założeniu, że HttpSessionState serializuje/deserializuje przy każdym dostępie. – Auraseer

+0

Brakowało części do serializacji/deklinalizacji. Powinienem był uważniej przeczytać to pytanie. –

-1

można spodziewać ustawiaczy i usługi na miano jeżeli:

  • są publicznie dostępne (widoczne dla innych zespołów).
  • Implementują program ustawiający jako część interfejsu widocznego dla innych zespołów. W niektórych przypadkach, takich jak
  • Są one używane w wiązaniu WPF (ale struktura będzie zgodna z regułami dotyczącymi BindingMode).
  • Używane są w MEF z ImportAttribute.
  • Są one używane w innych wiążących ramach (masz pomysł).

Nie powinieneś mieć problemów, jeśli dla interfejsów zdefiniowanych przez innych spełnione są warunki wstępne i końcowe operacji.

Edytuj: Zgadzam się z powyższymi. Mój pierwszy wybór do wystawiania kolekcji jest:

private readonly List<T> _sources = new List<T>(); 

/* Or ICollection<T>, ReadOnlyCollection<T>, or IList<T>, or 
* (only a real option for `internal` types) List<T> 
*/ 
public IEnumerable<T> Sources 
{ 
    get 
    { 
     return _sources; 
    } 
} 

Jeśli absolutnie musi zainicjować listy po utworzeniu obiektu, a następnie można użyć coś takiego jak druga opcja:

public IList<T> Sources 
{ 
    get; 
    private set; 
} 

Są sytuacje, w których powyższe praktyki niekoniecznie są najlepszą odpowiedzią, ale są to dwa najpowszechniejsze (IMO?).

+0

-1, odpowiedź jest całkowicie wyłączona z tematu oryginalnego wpisu. OP zapytał, dlaczego dany kod działa i czy mógł oczekiwać błędu z powodu ponownego utworzenia obiektu. –

Powiązane problemy