2010-01-26 17 views
10

Sono su un progetto ASP.Net 2.0, in C#. Ho alcuni dati che vengono memorizzati nello stato di sessione. Per facilità d'uso, è racchiuso in una proprietà, come questa:I setter della proprietà .Net vengono mai chiamati implicitamente?

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

Ottenere e impostare il valore funziona esattamente come ci si aspetterebbe. Se voglio cancellare il valore, lo imposto su null e non ci sono problemi. Tuttavia, nella pagina di un altro sviluppatore, chiama il metodo Clear() della raccolta. Ho pensato che sarebbe stato un bug, ma sembra funzionare, e non capisco perché. Funziona in questo modo:

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

Perché funziona? La mia ingenua aspettativa sarebbe che la linea di mezzo carica il valore serializzato dalla sessione, deserializza in un oggetto, chiama Clear() su quell'oggetto e quindi lascia l'oggetto senza nome fuori dall'ambito. Questo sarebbe un bug, perché il valore memorizzato in Session rimarrebbe invariato. Ma a quanto pare, è abbastanza intelligente chiamare invece il setter della proprietà e serializzare nuovamente la nuova collezione modificata in sessione.

Questo mi rende un po 'nervoso, perché ci sono posti nel nostro codice legacy in cui i setter hanno effetti collaterali, e non voglio che quelli vengano chiamati se non sono destinati.

Il setter della proprietà viene sempre chiamato in una situazione come questa? Sta succedendo qualcos'altro? O ho completamente frainteso cosa sta succedendo qui?

[Aggiunto per spiegare la risposta]
Si è verificato un equivoco. Sapevo che gli oggetti archiviati in Session devono essere serializzabili e sulla base di ciò ho fatto troppe ipotesi su come la raccolta si comporta internamente. Stavo pensando troppo.

C'è solo un'istanza dell'oggetto memorizzato (my IList). Ogni chiamata al getter restituisce un riferimento alla stessa istanza. Quindi il codice sopra riportato funziona esattamente come appare, senza richiedere magie speciali.

E per rispondere alla domanda del titolo: No, i setter non sono chiamati implicitamente.

risposta

4

Sì, hai ragione, questo sarebbe un bug se i tuoi setter/getter stavano serializzando/deserializzando gli oggetti. Ma questo non è il caso. Invece stai passando in base al riferimento.

Quindi, in pratica, la prima riga dell'esempio ottiene l'elemento tramite get e Count viene chiamato in base a questo. Poi la linea seccond sta uscendo e le chiamate ritornano, restituendo lo stesso oggetto, eseguendo clear, e quindi la terza riga sta facendo lo stesso della prima.

Se tu avessi scritto il tuo setter/getter qualcosa di simile, si avrebbe un "bug"

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

In questo caso, un nuovo oggetto sarebbe stato creato e per ogni chiamata al blocco get. Ma dal momento che il tuo esempio sopra sta semplicemente passando attorno al riferimento allo stesso oggetto, non vedrai questo "bug".

E dico "bug" poiché non è proprio un bug, è solo più di un fraintendimento di ciò che accade dietro le quinte.

Spero che questo aiuti.

+0

Aha! Avevo pensato che, poiché i valori in Session dovevano essere serializzabili, sarebbero stati memorizzati in uno stato serializzato, e ognuno avrebbe restituito un riferimento diverso. Se questo non è il caso, ed è abbastanza intelligente da restituire lo stesso riferimento su più chiamate, allora stavo proprio pensando troppo. – Auraseer

1

Il codice è più o meno equivalente a:

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 

Anche se si chiama solo il getter, si sta cancellando la collezione. Quindi l'output di debug sembra normale.

+5

+1. In effetti, la migliore pratica per le proprietà di colletion è di renderli di sola lettura (nessun setter). –

+0

Penso che tu abbia perso il mio punto. So cosa fa la proprietà accessor, ma il mio errore era nel presupporre che HttpSessionState serializza/deserializza su ogni accesso. – Auraseer

+0

Ho perso la parte di serializzazione/de-serializzazione. Avrei dovuto leggere la domanda con più attenzione. –

-1

si può aspettare setter di proprietà di essere chiamato se:

  • L'sono visibili pubblicamente (visibile ad altri assembly).
  • Implementano il setter come parte di un'interfaccia visibile ad altri assiemi. In alcuni casi, ad esempio
  • Vengono utilizzati nel binding WPF (ma il framework seguirà le regole relative allo BindingMode).
  • Sono utilizzati in MEF con ImportAttribute.
  • Sono utilizzati in altri framework vincolanti (si ottiene l'idea).

Non si dovrebbe incorrere in problemi se, per le interfacce definite da altri, si soddisfano le pre e post-condizioni dell'operazione.

Modifica: Sono d'accordo con quanto sopra. La mia prima scelta per l'esposizione di una collezione è:

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

Se deve assolutamente inizializzare la lista dopo la creazione dell'oggetto, quindi è possibile utilizzare qualcosa di simile come la seconda opzione:

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

Ci sono situazioni in cui le pratiche di cui sopra non sono necessariamente la risposta migliore, ma queste sono le due più comuni (IMO?).

+0

-1, la risposta è completamente fuori dall'argomento del post originale. OP ha chiesto perché il codice dato funzionava e se poteva aspettarsi un bug a causa della creazione dell'oggetto. –

Problemi correlati