如果对象是垃圾回收,如何获得通知?

B3r*_*ret 2 .net c# caching garbage-collection observer-pattern

精简版:

对于缓存类,如果对象被垃圾收集(从我的缓存中删除相应的条目),我需要得到通知.这样做的最佳方法是什么?从析构函数发送事件?

长版:

我正在编写一个cacher/memoizer,用于获取一个巨大的参数树对象和许多小值类型参数的函数,例如,

double myFunc(HugeParTree parTree, int dynPar1, double dynPar2)
Run Code Online (Sandbox Code Playgroud)

我想以下列方式缓存这些函数:

  • 缓存元组的结果(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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

我还没有测试过这个,因为我仍然有一个问题,即在不再使用相应的parTree后,缓存条目永远不会被删除.我喜欢同步解决方案,而不会对非常旧的缓存条目重复"扫描".

Hen*_*man 8

对于缓存类,如果对象被垃圾收集(从我的缓存中删除相应的条目),我需要得到通知.这样做的最佳方法是什么?从析构函数发送事件?

如果您的缓存包含正常(强)引用,则永远不会收集这些项.

如果您的缓存包含WeakReferences,则不必删除任何内容.

  • 你应该不时删除死的`WeakReference`.否则他们只会乱丢你的记忆. (5认同)