Короткая версия:
Для класса кеша мне нужно получать уведомление, если объект собирает мусор (чтобы удалить соответствующие записи из моего кеша).Каков наилучший способ сделать это?Отправка события из деструктора?
Длинная версия:
Я пишу кеширование / памятку для функций, которые принимают один огромный объект дерева параметров и множество параметров типа малых значений, например,
double myFunc(HugeParTree parTree, int dynPar1, double dynPar2)
Я хочу кэшировать эти функции следующим образом:
- Кэшировать результаты для кортежей (parTree.GUID, dynPar1, dynPar2, ...)
- Когда
parTree
изменяется, что случается редко, все соответствующие записи в кэше удаляются (через шаблон Observer).(parTree.Equals()
слишком дорого; сравнивает более 100 типов значений).
Код выглядит прямо сейчас (для одного параметра значения):
public class CachedFunction1ObsPar1Par<TRet, TObsPar1, TPar1>
where TObsPar1 : IObservable, IProvideGUID
{
public delegate TRet ValueCalculator(TObsPar1 obsPar1, TPar1 par1);
public CachedFunction1ObsPar1Par(ValueCalculator calc)
{
_calc = calc;
}
#region members
private ValueCalculator _calc;
private Dictionary<Guid, Dictionary<TPar1, TRet>> _cache =
new Dictionary<Guid, Dictionary<TPar1,TRet>>();
#endregion
public TRet value(TObsPar1 obsPar1, TPar1 par1)
{
TRet result;
bool cacheHit = checkCache(obsPar1, par1, out result);
if (cacheHit)
{
Debug.Assert(result.Equals(_calc(obsPar1, par1)));
return result;
}
else
{
result = _calc(obsPar1, par1);
_cache[obsPar1.GUID].Add(par1, result);
return result;
}
}
private bool checkCache(TObsPar1 obsPar1, TPar1 par1, out TRet result)
{
if (!_cache.ContainsKey(obsPar1.GUID))
{
_cache.Add(obsPar1.GUID, new Dictionary<TPar1, TRet>());
obsPar1._changed += this.invalidateCache;
}
Dictionary<TPar1, TRet> guidCache = _cache[obsPar1.GUID];
bool success = guidCache.TryGetValue(par1, out result);
return success;
}
private void invalidateCache(object sender)
{
TObsPar1 obsPar = (TObsPar1)sender;
_cache.Remove(obsPar.GUID);
obsPar._changed -= this.invalidateCache;
}
}
У меня естьеще не проверил это, так как у меня все еще есть проблема, что записи в кэше никогда не удаляются после того, как соответствующее parTree больше не используется.Мне бы хотелось синхронное решение без повторных «проверок» для очень старых записей в кэше.