有时我需要在一段时间内在内存中保留对对象的引用。弱引用允许这样做,但时间受到垃圾收集周期的限制。该问题与此类似,但与 .NET 相关。
我知道有许多缓存内置了这样的功能,但我不需要利用完整缓存(即键值映射(来仅存储一个对象。它宁愿是一个单一的"可过期参考"。
我知道我可以自己实现它,但我正在寻找一个标准的实现(理想情况下集成在框架中,以防我错过它(
更新
根据@Jeroen Mostert和@dariogriffo的回答,我为这个问题添加了更多细节。
好的,所以有两种方法:要么使用键值缓存,要么使用基于计时器的回调。假设有一个对象树,每个对象都有一个对缓存值的引用。这些值具有过期超时。假设树节点的计数很大。如果我将每个值存储在 MemoryCahce 中,则需要为节点分配唯一键,并且通过哈希表搜索访问它们的值。此外,它还具有向表添加新键的计算复杂性。另一方面,如果我按照@dariogriffo的建议使用我的自定义WeakReferenceByTimeOut
,那么它就没有这样的问题。相反,存在开销,因为我需要为每个值对象创建一个计时器对象(或我猜在内部使用计时器的 Task 对象(。从我的角度来看,第二种方法更好,但我不确定。
据我所知,也没有内置任何东西,所以这里有 1 分钟的实现
using System.Timers;
public class WeakReferenceByTimeOut<T> where T : class
{
private Timer _timer;
public WeakReferenceByTimeOut(T val, int miliseconds)
{
Reference = val;
_timer = new Timer(miliseconds);
_timer.Elapsed += KillReference;
_timer.AutoReset = false;
_timer.Enabled = true;
}
public T Reference { get; private set; }
private void KillReference(object sender, ElapsedEventArgs e)
{
_timer.Elapsed -= KillReference;
_timer.Dispose();
_timer = null;
Reference = null;
}
}
的有效期不应超过一定时间对您的要求很重要,那么,您确实需要某种缓存,即使它只是一个缓存。最简单的实现(如果您从未设置对其他任何内容的引用(是 Task.Delay(...).ContinueWith(t => myWeakReference = null)
,它不需要额外的类。如果您确实需要能够设置对其他内容的引用(这意味着重置计时器(,则需要一个包装类。
顺便说一下,我不建议编写一个支持将引用设置为其他内容的类 - 设置引用和在计时器到期时清除它之间存在固有的竞争条件。如果您需要这样的东西,几乎可以肯定,带有策略的经过审查的缓存实现会更好,即使您仅将其用于一个参考。
BCL中没有这样的事情;这是一个不寻常的情况。通常,您要么缓存多个值,要么不关心何时清理引用,只要缓存保持在一定的内存限制内。如果你有一个带有超时策略的缓存,如System.Runtime.Caching.MemoryCache,你可以在其中存储WeakReference
实例,这应该实现同样的事情(但你需要仔细检查你从缓存中返回的条目是否仍然有效(。