具有到期时间的字典缓存

问题描述 投票:1回答:4

我想创建一个类来返回一个值。此值将缓存在字典对象中2分钟。在这2分钟内,我需要返回缓存的值,在那几分钟之后,字典缓存对象应该再次读取该值。我需要使用Dictionary对象而不是memorychache或者其他东西我应该在Test方法类中执行代码而不是windows窗体或wpf。

我不知道如何在测试方法中使字典对象在2分钟后过期。

public class CacheClass
{
   public string GetValue()
   {
      Dictionary<int, string> Cache = new Dictionary<int, string>();
      string value1 = "Lina";
      string value2 = "Jack";

      return "cached value";
   }
}
c# unit-testing dictionary caching
4个回答
4
投票
public class Cache<TKey, TValue>
{
    private readonly Dictionary<TKey, CacheItem<TValue>> _cache = new Dictionary<TKey, CacheItem<TValue>>();

    public void Store(TKey key, TValue value, TimeSpan expiresAfter)
    {
        _cache[key] = new CacheItem<TValue>(value, expiresAfter);
    }

    public TValue Get(TKey key)
    {
        if (!_cache.ContainsKey(key)) return default(TValue);
        var cached = _cache[key];
        if (DateTimeOffset.Now - cached.Created >= cached.ExpiresAfter)
        {
            _cache.Remove(key);
            return default(TValue);
        }
        return cached.Value;
    }
}

public class CacheItem<T>
{
    public CacheItem(T value, TimeSpan expiresAfter)
    {
        Value = value;
        ExpiresAfter = expiresAfter;
    }
    public T Value { get; }
    internal DateTimeOffset Created { get; } = DateTimeOffset.Now;
    internal TimeSpan ExpiresAfter { get; }
}

var cache = new Cache<int, string>();
cache.Store(1, "SomeString", TimeSpan.FromMinutes(2));

1
投票

我将创建一个新的缓存项类型,跟踪值以及项添加到缓存的时间:

class CacheItem<T>
{
    public T Value { get; }
    public DateTime TimeAdded { get; }
    public bool IsValid => (DateTime.UtcNow - TimeAdded) < _timeToLive;

    private readonly TimeSpam _timeToLive = TimeSpan.FromMinutes(2);

    public CacheItem(T value)
    {
        Value = value;
        TimeAdded = DateTime.UtcNow;
    }
}

然后将缓存集合更改为Dictionary<int, CacheItem<string>>

public string GetValue(int key)
{
    CacheItem<string> item;
    if (_cache.TryGetValue(key, out item) && item.IsValid)
        return item.Value;
    return null; // Signifies no entry in cache or entry has expired.
}

1
投票

您需要将日期时间存储在缓存中。这样,您可以测试项目是否已过期。如果物品未找到或过期?为它调用resolvefunction。

这是一个缓存的例子,可以通过调用回调函数来填充它:

public class MyCache<TKey, TValue>
{
    // type to store datetime and a value
    private struct CacheItem
    {
        public DateTime RetreivedTime;
        public TValue Value;
    }

    // the dictionary
    private Dictionary<TKey, CacheItem> _cache = new Dictionary<TKey, CacheItem>();

    private TimeSpan _timeout;
    private Func<TKey, TValue> _resolveFunc;

    public MyCache(TimeSpan timeout, Func<TKey, TValue> resolveFunc)
    {
        // store to fields
        _timeout = timeout;
        _resolveFunc = resolveFunc;
    }

    public TValue this[TKey key]
    {
        get
        {
            CacheItem valueWithDateTime;

            // if nothing is found, you should resolve it by default
            var getNewValue = true;

            // lookup the key
            if (_cache.TryGetValue(key, out valueWithDateTime))
                // test if the value RetreivedTime was expired?
                getNewValue = valueWithDateTime.RetreivedTime.Add(_timeout) > DateTime.UtcNow;

            // was it found? or expired?
            if (getNewValue)
            {
                valueWithDateTime = new CacheItem { RetreivedTime = DateTime.UtcNow, Value = _resolveFunc(key) };
                _cache[key] = valueWithDateTime;
            }

            // return the value
            return valueWithDateTime.Value;
        }
    }

    // the cleanup method, you should call it sometimes...
    public void Cleanup()
    {
        var currentDateTime = DateTime.UtcNow;

        // ToArray prevents modifying an iterated collection.
        foreach (var keyValue in _cache.ToArray())
            if (keyValue.Value.RetreivedTime.Add(_timeout) < currentDateTime)
                _cache.Remove(keyValue.Key);
    }
}

缓存文本文件的示例:

class Program
{
    static string RetreiveFileContent(string filename)
    {
        if(!File.Exists(filename))
            return default(string);

        return File.ReadAllText(filename);
    }

    static void Main(string[] args)
    {
        var textFileCache = new MyCache<string, string>(TimeSpan.FromMinutes(2), RetreiveFileContent);

        var content = textFileCache["helloworld.txt"];

        // sometimes you need to cleanup old data.
        textFileCache.Cleanup();
    }
}

你需要创建一些事件的异常处理....


0
投票

我想你想要更简单的事情。根据你的解释,我无法弄清楚为什么你需要一个字典或集合?因为,你的CacheClass只有一个GetValue方法,而且一个项目不是从外面添加的。

所以,试试这样的事情也许会给你一个起点;

public class CacheObject
{
    public string Value { get; set; }

    public DateTime CreationDate { get; set; }

    public CacheObject()
    {
        CreationDate = DateTime.Now;
    }
}

public static class CacheClass
{
    private static Dictionary<int,CacheObject> _cache = new Dictionary<int, CacheObject>();

    public static string GetValue()
    {
        if (_cache.Count == 0 || _cache[0].CreationDate.AddMinutes(2) < DateTime.Now)
        {
            var cache = new CacheObject
            {
                Value = GetValueFromSource()
            };
            _cache[0] = cache;
        }
        return _cache[0].Value;
    }

    public static string GetValueFromSource()
    {
        return "Jack";
    }
}

用法;

var str = CacheClass.GetValue();
© www.soinside.com 2019 - 2024. All rights reserved.