2017-12-18 26 views
0

値を返すクラスを作成したいと思います。この値はディクショナリオブジェクトに2分間キャッシュされます。この2分間、キャッシュされた値を返す必要があります。その分後に辞書キャッシュオブジェクトは値を再び読み取る必要があります。私はmemorychacheや何かではないDictionaryオブジェクトを使用する必要がありますし、WindowsフォームやwpfではなくTestメソッドクラスでコードを実行する必要があります。有効期限のある辞書キャッシュ

テストメソッドで2分後に辞書オブジェクトが期限切れになる方法を知りません。

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

     return "cached value"; 
    } 
} 
+0

新しいタイプ(CacheItem 多分?)を作成して、彼は辞書 '辞書>'です。 'CacheItem '型は 'T'(値が何であれ)を保持し、値がキャッシュにいつ追加されたかを記録する' DateTime'を保持します。次に、キャッシュされた値が返される前に有効かどうかを確認するだけで、再評価が必要かどうかを判断できます。 – itsme86

+0

MemoryCacheを使用してみませんか?マイクロソフトは最近、MemoryCacheを以前使用した手荷物のない名前空間に移行しました。 https://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache(v=vs.110).aspx – mageos

+0

キャッシュされた値を追跡するためにDatetimeを作成するにはどうすればよいですか? –

答えて

2
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)); 
+0

**テストメソッド**は有効期限を待つのに約2分しか実行しませんか?私は 'IDateTimeService'キャッシュクラスへ –

+0

ユニットテストを2分間実行したくない場合。理想的には、いくつかの抽象概念を持つことは良いことであり、いくつかの '.Now'プロパティにはあまり依存しません。しかし、このケースでは、それはその答えを劇的に複雑にするでしょう。実際には、キャッシュの持続時間が<50msで、Thread.Sleep(200)というようなものでこれをテストすることもできます。 –

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. 
} 
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(); 
1

キャッシュに保存された日時を保存する必要があります。この方法でアイテムが期限切れになっているかどうかテストできます。アイテムが見つからないか、期限が切れていれば?そのためにresolve関数を呼び出します。ここで

は、コールバック関数を呼び出すことによって、自己それを埋めることができますキャッシュの例です:キャッシュテキストファイル用

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(); 
    } 
} 

あなたは、いくつかの例外処理を作成する必要がありますofcourse ....

関連する問題