Creo que se está preguntando cuántas copias del objeto Cache
se crearán. Solo desea que una copia sea compartida por varios objetos de cliente. Bueno, hay una regla muy simple que puedes recordar en C#, siempre que quieras saber cuántas copias separadas de tu objeto se crearán.
Si el tipo de objeto se declara con la palabra clave class
, entonces hay una sola manera de hacer una nueva instancia de que: con la palabra clave new
.
Existen pequeñas excepciones a esto: puede llamar a los métodos BCL que crean objetos, pero el punto es que es explícito. Tienes que pedir específicamente que suceda. El idioma no hará automáticamente copias de los objetos class
.
Así que en tu ejemplo, que tienen un class
llamados Cache
, y por lo que sabemos con certeza que se puede pasar alrededor de variables de tipo Cache
tanto como te gusta, y no se crearán más copias de Cache
. Todas las variables que tienen asignado ese objeto serán "apuntando" al mismo objeto original. Esto se debe a que una variable Cache
no almacena el objeto en sí, sino solo la ubicación de un objeto Cache
en la memoria.
Contraste esto con lo que sucede si declara un tipo struct
en lugar de class
. Ahora cuando declara una variable de ese tipo, la variable en sí tiene que ser lo suficientemente grande como para almacenar todos los datos declarados en el struct
. Cada variable es una copia separada. Cada parámetro es una copia separada.
Puede anular esto agregando la palabra clave ref
, pero es una palabra clave bastante inusual en la mayoría de los programas. La palabra clave out
es más común, y se considera mejor como una forma de dar a un método más de un valor de retorno.
¿Qué efecto tiene ref
en una variable si es de tipo class
? En su ejemplo:
public ObjectLoader(Cache cache) {
// do stuff with cache (store it?)
}
que podría construir dos cargadores objeto de esta manera:
Cache c = new Cache();
ObjectLoader a = new ObjectLoader(c),
ObjectLoader b = new ObjectLoader(c);
¿Cuántos objetos qué acabamos de crear? Simplemente cuente las palabras clave new
. Ahora, supongamos que agregamos la palabra clave ref
:
public ObjectLoader(ref Cache cache) {
_cache = cache; // store
// do something very odd!
cache = new Cache();
}
escondido dentro de ese constructor, he creado otro caché, y se almacena en el parámetro me pasaron. ¡Debido a que es un parámetro ref
, he afectado la variable de la persona que llama! Así que en el código de llamada:
Cache c = new Cache();
ObjectLoader a = new ObjectLoader(ref c),
ObjectLoader b = new ObjectLoader(ref c);
Ahora tenemos cinco usos de new
: tres en el fragmento anterior, además de dos llamadas a la ObjectLoader
constructor modificado. Cada vez que se llama al constructor ObjectLoader
, lo pasamos c
. Tenemos que poner la palabra clave ref
, que es algo muy bueno porque le permite a la persona que lee el código saber que algo extraño está sucediendo.La variable c
apunta a un Cache
diferente después de que el constructor ObjectLoader
retorna. Así que b
's ObjectLoader
termina almacenando un puntero a un Cache
diferente a a
!
No hace falta decir que este sería un patrón bastante complicado para el código. ¡Sería aún peor si no tuviéramos que poner la palabra clave ref
en el sitio que llama!
Es mucho más simple con los punteros C/C++ normales :) – Eugene
No estoy de acuerdo :) Pero para las personas c/C++ es la diferencia entre * (o &) y ** :) – Stormenet
nitpick: segundo ejemplo - usted es acceder a una propiedad estática. – Cherian