Compactando um Dicionário WeakReference

Eu tenho uma aulaFoo com uma propriedadeIdentidade. Meu objetivo é que não haja duas instâncias deFoo com o mesmoIdentidade ao mesmo tempo.

Então eu criei um método de fábricaCreateFoo que usa um cache para retornar a mesma instância para o mesmoIdentidade.

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

O cache é implementado como um Dictionary <TKey, WeakReference>, com base em@JaredPar'sConstruindo uma Hashtable WeakReference:

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

O problema é que os WeakReferences permanecem no dicionário depois que seus alvos foram coletados como lixo. Isto implica a necessidade de alguma estratégia como manualmente "coleta de lixo" mortos WeakReferences, como explicado por@Pascal Cuoq&nbsp;emO que acontece com um WeakReference após GC de WeakReference.Target.

Minha pergunta é:Qual é a melhor estratégia para compactar um dicionário WeakReference?

As opções que vejo são:

Não remova WeakReferences do dicionário. IMO isso é ruim, porque o cache é usado no tempo de vida completo do meu aplicativo, emuito&nbsp;de WeakReferences mortos irá acumular ao longo do tempo.

Ande o dicionário inteiro em cadaColocar&nbsp;eTryGetValuee remova WeakReferences mortos. Isso anula um pouco o propósito de um dicionário porque ambas as operações se tornamEm).

Ande o dicionário inteiro periodicamente em um segmento de plano de fundo. Qual seria um bom intervalo, dado que não sei o padrão de uso deCreateFoo?

Anexe cada KeyValuePair inserido a uma lista encadeada de final duplo. Cada chamada paraColocar&nbsp;eTryGetValue&nbsp;examina o chefe da lista. Se o WeakReference estiver ativo, mova o par para o final da lista. Se estiver morto, remova o par da lista e o WeakReference do Dicionário.

Implemente uma tabela de hash personalizada com a menor diferença de que, quando um bucket está cheio, WeakReferences mortos são removidos primeiro do bucket antes de continuar como de costume.

Existem outras estratégias?

A melhor estratégia é provavelmente um algoritmo com complexidade de tempo amortizado. Existe tal estratégia?