Вы можете удалить «недействительный» WeakReference
внутри TryGetValue
:
[Edit] Моя ошибка, эти решения на самом деле не делают ничего, кроме того, что вы предложили, так как метод Put
все равно заменит старый объект новым. Просто игнорируй это.
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;
if (value == null)
this.items.Remove(key);
return (value != null);
}
}
Или вы можете немедленно создать новый экземпляр внутри своего словаря, когда это необходимо:
public TValue GetOrCreate(TKey key, Func<Tkey, TValue> ctor) {
WeakReference weakRef;
if (!this.items.TryGetValue(key, out weakRef) {
Tvalue result = ctor(key);
this.Put(key, result);
return result;
}
value = (TValue)weakRef.Target;
if (value == null)
{
Tvalue result = ctor(key);
this.Put(key, result);
return result;
}
return value;
}
Тогда вы бы использовали это так:
static Foo CreateFoo(int id)
{
return cache.GetOrCreate(id, id => new Foo(id));
}
[Редактировать]
Согласно сообщению windbg, один экземпляр WeakReference
занимает 16 байтов. Для 100 000 собранных предметов это не будет таким серьезным бременем, так что вы можете легко позволить им жить.
Если это серверное приложение, и вы полагаете, что вы могли бы выиграть от сбора, я бы подумал о переходе на фоновый поток, а также о реализации простого алгоритма для увеличения времени ожидания всякий раз, когда вы собираете относительно небольшое число объектов.