Skip to content

Commit

Permalink
Add TryGetValue (#142)
Browse files Browse the repository at this point in the history
Co-authored-by: Tom Almroth <[email protected]>
  • Loading branch information
talmroth and Tom Almroth committed Mar 15, 2021
1 parent 8d4b269 commit 33d055c
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 10 deletions.
25 changes: 21 additions & 4 deletions LazyCache.UnitTests/CachingServiceMemoryCacheProviderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ private static CachingService BuildCache()

private class ComplexTestObject
{
public readonly IList<object> SomeItems = new List<object> {1, 2, 3, "testing123"};
public readonly IList<object> SomeItems = new List<object> { 1, 2, 3, "testing123" };
public string SomeMessage = "testing123";
}

Expand Down Expand Up @@ -528,7 +528,7 @@ public async Task
Thread.Sleep(500);

Assert.That(callbackValue, Is.AssignableTo<Task<int>>());
var callbackResultValue = await (Task<int>) callbackValue;
var callbackResultValue = await (Task<int>)callbackValue;
Assert.AreEqual(123, callbackResultValue);
}

Expand Down Expand Up @@ -873,7 +873,7 @@ MemoryCacheEntryOptions GetOptions()
.SetAbsoluteExpiration(refreshInterval, ExpirationMode.ImmediateEviction);
options.RegisterPostEvictionCallback((keyEvicted, value, reason, state) =>
{
if (reason == EvictionReason.Expired || reason == EvictionReason.TokenExpired)
if (reason == EvictionReason.Expired || reason == EvictionReason.TokenExpired)
sut.GetOrAdd(key, _ => GetStuff(), GetOptions());
});
return options;
Expand Down Expand Up @@ -946,7 +946,7 @@ ComplexTestObject GetStuff()
{
var key = $"stuff-{hits % uniqueCacheItems}";
var cached = await sut.GetOrAddAsync(key, () => GetStuffAsync(), DateTimeOffset.UtcNow.AddSeconds(1));
if(!cancel.IsCancellationRequested) Interlocked.Increment(ref hits);
if (!cancel.IsCancellationRequested) Interlocked.Increment(ref hits);
}
});
});
Expand Down Expand Up @@ -1108,5 +1108,22 @@ public void RemovedItemCannotBeRetrievedFromCache()
sut.Remove(TestKey);
Assert.Null(sut.Get<object>(TestKey));
}

[Test]
public void TryGetReturnsCachedValueAndTrue()
{
string val = "Test Value";
string key = "testkey";
sut.Add(key, val);

var contains = sut.TryGetValue<string>(key, out var value);

Assert.IsTrue(contains);
Assert.AreEqual(value, val);

var contains2 = sut.TryGetValue<string>("invalidkey", out var value2);

Assert.IsFalse(contains2);
}
}
}
15 changes: 11 additions & 4 deletions LazyCache/CachingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public CachingService(ICacheProvider cache) : this(() => cache)
}

public static Lazy<ICacheProvider> DefaultCacheProvider { get; set; }
= new Lazy<ICacheProvider>(() =>
= new Lazy<ICacheProvider>(() =>
new MemoryCacheProvider(
new MemoryCache(
new MemoryCacheOptions())
Expand Down Expand Up @@ -89,6 +89,13 @@ public virtual Task<T> GetAsync<T>(string key)
return GetValueFromAsyncLazy<T>(item, out _);
}

public virtual bool TryGetValue<T>(string key, out object value)
{
ValidateKey(key);

return CacheProvider.TryGetValue(key, out value);
}

public virtual T GetOrAdd<T>(string key, Func<ICacheEntry, T> addItemFactory)
{
return GetOrAdd(key, addItemFactory, null);
Expand All @@ -112,7 +119,7 @@ object CacheFactory(ICacheEntry entry) =>
// acquire lock per key
uint hash = (uint)key.GetHashCode() % (uint)keyLocks.Length;
while (Interlocked.CompareExchange(ref keyLocks[hash], 1, 0) == 1) { Thread.Yield(); }

try
{
cacheItem = CacheProvider.GetOrCreate<object>(key, policy, CacheFactory);
Expand Down Expand Up @@ -179,7 +186,7 @@ public virtual Task<T> GetOrAddAsync<T>(string key, Func<ICacheEntry, Task<T>> a

public virtual async Task<T> GetOrAddAsync<T>(string key, Func<ICacheEntry, Task<T>> addItemFactory,
MemoryCacheEntryOptions policy)
{
{
ValidateKey(key);

object cacheItem;
Expand Down Expand Up @@ -280,7 +287,7 @@ protected virtual T GetValueFromLazy<T>(object item, out bool valueHasChangedTyp

protected virtual Task<T> GetValueFromAsyncLazy<T>(object item, out bool valueHasChangedType)
{
valueHasChangedType = false;
valueHasChangedType = false;
switch (item)
{
case AsyncLazy<T> asyncLazy:
Expand Down
2 changes: 2 additions & 0 deletions LazyCache/IAppCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ public interface IAppCache
void Add<T>(string key, T item, MemoryCacheEntryOptions policy);
T Get<T>(string key);
Task<T> GetAsync<T>(string key);
bool TryGetValue<T>(string key, out object value);

T GetOrAdd<T>(string key, Func<ICacheEntry, T> addItemFactory);
T GetOrAdd<T>(string key, Func<ICacheEntry, T> addItemFactory, MemoryCacheEntryOptions policy);
Task<T> GetOrAddAsync<T>(string key, Func<ICacheEntry, Task<T>> addItemFactory);
Expand Down
1 change: 1 addition & 0 deletions LazyCache/ICacheProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ public interface ICacheProvider : IDisposable
object GetOrCreate<T>(string key, MemoryCacheEntryOptions policy, Func<ICacheEntry, T> func);
void Remove(string key);
Task<T> GetOrCreateAsync<T>(string key, Func<ICacheEntry, Task<T>> func);
bool TryGetValue(object key, out object value);
}
}
6 changes: 6 additions & 0 deletions LazyCache/Mocks/MockCacheProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace LazyCache.Mocks
{

public class MockCacheProvider : ICacheProvider
{
public void Set(string key, object item, MemoryCacheEntryOptions policy)
Expand Down Expand Up @@ -34,6 +35,11 @@ public Task<T> GetOrCreateAsync<T>(string key, Func<ICacheEntry, Task<T>> func)
return func(null);
}

public bool TryGetValue(object key, out object value)
{
throw new NotImplementedException();
}

public void Dispose()
{
}
Expand Down
6 changes: 6 additions & 0 deletions LazyCache/Mocks/MockCachingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,11 @@ public Task<T> GetAsync<T>(string key)
public void Add<T>(string key, T item, MemoryCacheEntryOptions policy)
{
}

public bool TryGetValue<T>(string key, out object value)
{
value = default(T);
return true;
}
}
}
10 changes: 8 additions & 2 deletions LazyCache/Providers/MemoryCacheProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public object GetOrCreate<T>(string key, Func<ICacheEntry, T> factory)

public object GetOrCreate<T>(string key, MemoryCacheEntryOptions policy, Func<ICacheEntry, T> factory)
{
if(policy == null)
if (policy == null)
return cache.GetOrCreate(key, factory);

if (!cache.TryGetValue(key, out var result))
Expand All @@ -47,7 +47,7 @@ public object GetOrCreate<T>(string key, MemoryCacheEntryOptions policy, Func<IC
var expiryTokenSource = new CancellationTokenSource();
var expireToken = new CancellationChangeToken(expiryTokenSource.Token);
entry.AddExpirationToken(expireToken);
entry.RegisterPostEvictionCallback((keyPost, value, reason, state) =>
entry.RegisterPostEvictionCallback((keyPost, value, reason, state) =>
expiryTokenSource.Dispose());

result = factory(entry);
Expand Down Expand Up @@ -78,6 +78,12 @@ public Task<T> GetOrCreateAsync<T>(string key, Func<ICacheEntry, Task<T>> factor
return cache.GetOrCreateAsync(key, factory);
}

public bool TryGetValue(object key, out object value)
{
return cache.TryGetValue(key, out value);
}


public void Dispose()
{
cache?.Dispose();
Expand Down

0 comments on commit 33d055c

Please sign in to comment.