Compactando un diccionario de referencia débil

Tengo una claseFoo con una propiedadCarné de identidad. Mi objetivo es que no haya dos instancias deFoo con el mismoCarné de identidad al mismo tiempo.

Así que creé un método de fábrica.CrearFoo que utiliza un caché para devolver la misma instancia para el mismoCarné de identidad.

static Foo CreateFoo(int id) {
    Foo foo;
    if (!cache.TryGetValue(id, out foo)) {
        foo = new Foo(id);
        foo.Initialize(...);
        cache.Put(id, foo);
    }
    return foo;
}

El caché se implementa como un Diccionario <TKey, WeakReference>, basado en@JaredParesConstruyendo un HashReference Weaktable:

class WeakDictionary<TKey, TValue> where TValue : class {
    private readonly Dictionary<TKey, WeakReference> items;
    public WeakDictionary() {
        this.items = new Dictionary<TKey, WeakReference>();
    }
    public void Put(TKey key, TValue value) {
        this.items[key] = new WeakReference(value);
    }
    public bool TryGetValue(TKey key, out TValue value) {
        WeakReference weakRef;
        if (!this.items.TryGetValue(key, out weakRef)) {
            value = null;
            return false;
        } else {
            value = (TValue)weakRef.Target;
            return (value != null);
        }
    }
}

El problema es que las WeakReferences permanecen en el diccionario después de que se hayan recolectado sus objetivos. Esto implica la necesidad de alguna estrategia sobre cómo "recolectar basura" manualmente. Referencias débiles, como se explica en@Pascal Cuoq en¿Qué sucede con una WeakReference después de GC de WeakReference.Target?.

Mi pregunta es:¿Cuál es la mejor estrategia para compactar un diccionario de WeakReference?

Las opciones que veo son:

No elimines WeakReferences del Diccionario. En mi opinión, esto es malo, porque el caché se usa durante toda la vida de mi aplicación, ymucho Las referencias débiles muertas se acumularán con el tiempo.

Camina todo el diccionario en cadaPoner yTryGetValue, y eliminar WeakReferences muertos. Esto derrota un tanto el propósito de un diccionario porque ambas operaciones se convierten enEn).

Camina todo el diccionario periódicamente en un hilo de fondo. ¿Cuál sería un buen intervalo, dado que no conozco el patrón de uso deCrearFoo?

Agregue cada KeyValuePair insertado a una lista enlazada de doble final. Cada llamada aPoner yTryGetValue Examina el jefe de la lista. Si el WeakReference está vivo, mueva el par al final de la lista. Si está muerto, elimine el par de la lista y la WeakReference del Diccionario.

Implemente una tabla hash personalizada con la pequeña diferencia de que, cuando un grupo está lleno, las WeakReferences muertas primero se eliminan del grupo antes de proceder como de costumbre.

¿Hay otras estrategias?

La mejor estrategia es probablemente un algoritmo con complejidad de tiempo amortizado. ¿Existe tal estrategia?

Respuestas a la pregunta(7)

Su respuesta a la pregunta