#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.