#retosMSDN: Solución al Reto 6 – Caché de objetos en C#
Aquí tienes la solución que proponemos para el sexto de nuestros #retosMSDN: Reto 6 – Caché de objetos en C#. ¡Muchas gracias a todos los que habéis participado en el reto!
Nuestra solución
Para que nuestra caché pueda guardar referencias a objetos que el Garbage Collector pueda liberar si nadie más los referencia, tenemos que utilizar WeakReferences.
Además, para modificar la información sobre el objeto caché que se verá en el depurador podemos utilizar los atributos de visualización del depurador.
Una posible implementación que cumple los requisitos del reto sería esta:
[DebuggerDisplay("Count = {Count}, ActiveCount = {ActiveCount}")]
[DebuggerTypeProxy(typeof(CacheDebugView))]
public class Cache
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private Dictionary<int, WeakReference> cache = new Dictionary<int, WeakReference>();
public void Add(int key, object value)
{
cache.Add(key, new WeakReference(value));
}
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public int Count
{
get { return cache.Count; }
}
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public int ActiveCount
{
get { return cache.Count(reference => reference.Value.IsAlive); }
}
public object this[int key]
{
get
{
return cache[key].Target;
}
}
internal class CacheDebugView
{
private Cache cache;
public CacheDebugView(Cache cache)
{
this.cache = cache;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public KeyValuePairs[] Keys
{
get
{
KeyValuePairs[] keys = new KeyValuePairs[cache.Count];
int i = 0;
foreach (int key in cache.cache.Keys)
{
keys[i] = new KeyValuePairs(key, cache[key]);
i++;
}
return keys;
}
}
}
}
[DebuggerDisplay("Key = {Key}, Value = {Value}")]
internal class KeyValuePairs
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private int Key { get; set; }
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private object Value { get; set; }
public KeyValuePairs(int key, object value)
{
this.Key = key;
this.Value = value;
}
}
El código completo lo puedes encontrar en esta solución de Visual Studio 2013 que puedes descargarte de GitHub.
Vuestras soluciones
La solución que nos ha planteado @lantoli es muy similar a la nuestra. Ahora, es interesante ver cómo usa linq, expresiones lambda e inicialización de objetos en su implementación de CacheDebugView:
[DebuggerDisplay("Key = {Key}, Value = {Value}")]
internal class Pair
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public object Key { get; set; }
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public object Value { get; set; }
}
internal class CacheDebugView
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly Cache cache;
public CacheDebugView(Cache cache)
{
this.cache = cache;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public Pair[] Pairs
{
get
{
return cache.dict.Select(x => new Pair { Key = x.Key, Value = x.Value.Target }).ToArray();
}
}
}
¡El próximo viernes 28 de noviembre publicaremos el siguiente de nuestros #retosMSDN! Y si quieres retar al resto de la comunidad con tu propio reto, recuerda que puedes enviárnoslo a esmsdn@microsoft.com.
Un saludo,
Alejandro Campos Magencio (@alejacma)
Technical Evangelist
PD: Mantente informado de todas las novedades de Microsoft para los desarrolladores españoles a través del Twitter de MSDN, el Facebook de MSDN, el Blog de MSDN y la Newsletter MSDN Flash.
Comments
- Anonymous
November 22, 2014
Me gusta mucho la iniciativa de los retos, por falta de tiempo no he podido hacer ninguno, pero bueno, los voy siguiendo. Me parece que sería bueno agregar un poco más de contexto teórico a las soluciones, en este caso, la documentación de MSDN sobre WeakReferences no es muy buena, por lo que estaría bueno disponer de más información, sobre todo porque muchos podemos tener algún bache de conocimiento sobre que pasa normalmente con las referencias fuertes, como el GC funciona, que es lo óptimo y que no, etc. Saludos!