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 어쩌면?)을 만들고 t 그는 사전 >'을 사용합니다. 'CacheItem '타입은'T' (값이 무엇이든간에)와 캐시에 값이 추가 된 시간을 추적하는'DateTime'을 포함합니다. 그런 다음 캐시 된 값이 반환되기 전에 유효한지 여부를 확인하고 다시 평가해야하는지 결정할 수 있습니다. – itsme86

+0

MemoryCache를 사용하지 않는 이유는 무엇입니까? Microsoft는 최근에 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

: 그런 다음 Dictionary<int, CacheItem<string>>에 캐시 모음을 변경

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

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

나는 더 간단한 것을 원한다고 생각합니다. 당신의 설명에 따르면, 왜 사전이나 컬렉션이 필요한지 알 수 없었습니다. CacheClassGetValue 메소드를 가지고 있으며 항목이 외부에서 추가되지 않았기 때문에

그래서 시작 지점을 제공 할 수도 있습니다.

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

캐시에 datetime을 저장해야합니다. 이렇게하면 만료 된 항목을 테스트 할 수 있습니다. 항목이 없거나 만료 된 경우? 그것에 대한 resolve 함수를 호출하십시오. 당신은 몇 가지 예외 처리를 만들 필요가

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

: 캐싱 textfiles에 대한

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

예 : 여기

는 콜백 함수를 호출하여 그것을 자기를 채울 수있는 캐시의 예 ofcourse ....