2010-01-26 4 views
10

Estoy en un proyecto ASP.Net 2.0, en C#. Tengo algunos datos que se almacenan en el estado de la sesión. Para facilitar su uso, está envuelto en una propiedad, como esta:¿Alguna vez se llama implícitamente a los establecedores de propiedades .Net?

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

Obtener y establecer el valor funciona exactamente como era de esperar. Si quiero borrar el valor, simplemente lo configuro como nulo y no hay problemas. Sin embargo, en la página de otro desarrollador, llama al método Clear() de la colección. Pensé que esto sería un error, pero parece funcionar, y no entiendo por qué. Funciona de la siguiente manera:

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

Por qué funciona esto? Mi ingenua expectativa sería que la línea media carga el valor serializado de la sesión, se deserializa en un objeto, llama al Clear() en ese objeto y luego deja que el objeto sin nombre se salga del alcance. Eso sería un error, porque el valor almacenado en Session se mantendría sin cambios. Pero, al parecer, es lo suficientemente inteligente como para llamar a la propiedad setter y serializar la colección nuevamente modificada nuevamente en la sesión.

Esto me pone un poco nervioso, porque hay lugares en nuestro código heredado donde los establecedores de propiedades tienen efectos secundarios, y no quiero que se llamen si no se pretende.

¿El sistema de establecimiento siempre se llama en una situación como esta? ¿Algo más está pasando? ¿O no entiendo completamente lo que está sucediendo aquí?

[Agregado a la explicación de la respuesta]
Resulta que no entendí bien. Sabía que los objetos almacenados en Session deben ser serializables y, en base a eso, hice demasiadas suposiciones sobre cómo se comporta la colección internamente. Estaba pensando demasiado.

Solo hay una instancia del objeto almacenado (mi IList). Cada llamada al getter devuelve una referencia a esa misma instancia. Por lo tanto, el código citado anterior funciona tal como aparece, sin necesidad de magia especial.

Y para responder a la pregunta del título: No, no se llaman implícitamente los ajustadores.

Respuesta

4

Sí, tienes razón, esto sería un error si tu setter/getters estuviera serializando/deserializando los objetos. Pero este no es el caso. En cambio, estás pasando según la referencia.

Entonces, básicamente, lo que ocurre es que la primera línea de su ejemplo obtiene el artículo a través de la obtención, y se llama a Count en función de eso. Luego, la segunda línea se apaga y la llamada vuelve a aparecer, devolviendo el mismo objeto, ejecutándose claro, y luego la tercera línea está haciendo lo mismo que la primera.

si hubiera escrito su setter/getter algo como esto, usted tendría un "error"

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

En este caso, un nuevo objeto sería creado y para cada llamada al bloque get. Pero como su ejemplo anterior es simplemente pasar la referencia al mismo objeto, no verá este "error".

Y digo "error", ya que no es realmente un error, es más una mala interpretación de lo que está sucediendo detrás de escena.

Espero que esto ayude.

+0

Aha! Había asumido que debido a que los valores en Session deben ser serializables, se almacenarían en estado serializado, y cada get devolvería una referencia diferente. Si ese no es el caso, y es lo suficientemente inteligente como para devolver la misma referencia en varias llamadas, entonces estaba pensando demasiado. – Auraseer

1

Su código es más o menos 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 

Incluso si sólo llamar al captador, están limpiando la colección. Entonces, la salida de depuración parece normal.

+5

+1. De hecho, la mejor práctica para las propiedades de la colección es hacerlas de solo lectura (sin setter). –

+0

Creo que no entendiste mi punto. Sé lo que hace el acceso a la propiedad, pero mi error fue suponer que HttpSessionState se serializa/deserializa en cada acceso. – Auraseer

+0

Me perdí la parte de serialización/deserialización. Debería haber leído la pregunta con más cuidado. –

-1

Puede esperar emisores de propiedad a ser llamados si:

  • El son visibles públicamente (visible para otros montajes).
  • implementan el setter como parte de una interfaz visible para otros conjuntos. En algunos casos, como
  • Se utilizan en WPF vinculante (pero el marco seguirán las reglas sobre el BindingMode).
  • Se utilizan en MEF con el ImportAttribute.
  • Se utilizan de alguna otra marco vinculante (se entiende la idea).

No debe tener problemas si, para interfaces definidas por otros, cumple con las condiciones previas y posteriores de la operación.

Editar: estoy de acuerdo con lo anterior. Mi primera opción para exponer una colección es:

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

Si es absolutamente necesario inicializar la lista después de que se crea el objeto, entonces se puede usar algo como esto como la segunda opción:

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

Hay situaciones en las que las prácticas anteriores no son necesariamente la mejor respuesta, pero estas son las dos más comunes (¿OMI?).

+0

-1, la respuesta está completamente fuera del tema de la publicación original. OP preguntó por qué el código dado estaba funcionando, y si podía esperar un error debido al objeto que se recreó. –

Cuestiones relacionadas