Skip to content

Instantly share code, notes, and snippets.

@markrendle
Created August 24, 2011 11:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save markrendle/1167813 to your computer and use it in GitHub Desktop.
Save markrendle/1167813 to your computer and use it in GitHub Desktop.
namespace ElegantCache
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.Caching;
class ElegantCache<TValue> : IDisposable
{
private readonly MemoryCache _cache = new MemoryCache(Guid.NewGuid().ToString());
private readonly CacheItemPolicy _cacheItemPolicy;
private readonly Func<TValue, string> _keyResolver;
private readonly Func<IEnumerable<string>, IEnumerable<TValue>> _uncachedResolver;
public ElegantCache(CacheItemPolicy cacheItemPolicy,
Func<TValue, string> keyResolver,
Func<IEnumerable<string>, IEnumerable<TValue>> uncachedResolver)
{
_cacheItemPolicy = cacheItemPolicy;
_keyResolver = keyResolver;
_uncachedResolver = uncachedResolver;
}
public IEnumerable<TValue> Get(string[] keys)
{
var values = _cache.GetValues(keys) ?? new Dictionary<string, object>();
if (values.Count(kvp => kvp.Value != null) < keys.Length)
{
GetUncachedValues(keys, values);
}
return keys.Select(key => values[key]).Cast<TValue>();
}
private void GetUncachedValues(string[] keys, IDictionary<string, object> values)
{
foreach (var value in _uncachedResolver(keys.Where(k => values[k] == null)))
{
var key = _keyResolver(value);
values[key] = value;
_cache.Set(key, value, _cacheItemPolicy);
}
}
public void Dispose()
{
_cache.Dispose();
}
}
public class ClientProxy : IDisposable
{
readonly ElegantCache<JsonDocument> _cache =
new ElegantCache<JsonDocument>(new CacheItemPolicy(), json => json.ID, GetDocumentsFromServer);
public JsonDocument[] GetDocument(params string[] ids)
{
return _cache.Get(ids).ToArray();
}
private static IEnumerable<JsonDocument> GetDocumentsFromServer(IEnumerable<string> ids)
{
var request = WebRequest.Create("http://server/get?id=" + string.Join("&id=", ids));
using (var stream = request.GetResponse().GetResponseStream())
{
return GetResults(stream);
}
}
private static JsonDocument[] GetResults(Stream stream)
{
// Parse stream
}
public void Dispose()
{
_cache.Dispose();
}
}
public class JsonDocument
{
public string ID { get; set; }
}
}
@markrendle
Copy link
Author

The eventual, non-memory-leaking, thread-safe, performant and still, I think, elegant solution to Ayende's challenge here: http://ayende.com/blog/60417/elegancy-challenge-cacheable-batches

@MrDustpan
Copy link

Very nice solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment