Skip to content

Instantly share code, notes, and snippets.

@RichCzyzewski
Created January 27, 2012 03:53
Show Gist options
  • Save RichCzyzewski/1686880 to your computer and use it in GitHub Desktop.
Save RichCzyzewski/1686880 to your computer and use it in GitHub Desktop.
Caching Method Returns w/Instance Leaning Towards Generics
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Text;
namespace Testing_MethodReturnCache
{
class Program
{
static void Main(string[] args)
{
var returnCache = new ReturnCache();
var result = returnCache.GetOrAdd(GetSomeLongRunningMethodsResult, "testing", 10);
var cachingStopwatch = Stopwatch.StartNew();
result = returnCache.GetOrAdd(GetSomeLongRunningMethodsResult, "testing", 10);
cachingStopwatch.Stop();
Console.WriteLine(string.Format("Result: {0} Cached Ticks: {1}", result, cachingStopwatch.ElapsedTicks));
Console.ReadLine();
}
public static string GetSomeLongRunningMethodsResult(string someString, int someNumber)
{
Thread.Sleep(5000);
return someString + someNumber.ToString();
}
}
public class ReturnCache
{
private ConcurrentDictionary<dynamic, dynamic> _funcCacheLookup = new ConcurrentDictionary<dynamic, dynamic>();
public TResult GetOrAdd<T1, T2, TResult>(Func<T1, T2, TResult> func, T1 arg1, T2 arg2)
{
dynamic value;
if (!_funcCacheLookup.TryGetValue(func, out value))
{
var cache = new ReturnCacheInternal<T1, T2, TResult>(func);
_funcCacheLookup[func] = cache;
value = cache;
}
return ((ReturnCacheInternal<T1, T2, TResult>)value).GetCacheableValue(arg1, arg2);
}
private class ReturnCacheInternal<T1, T2, TResult>
{
private Func<T1, T2, TResult> _retrievalFunc;
private readonly object _syncRoot = new object();
private ConcurrentDictionary<Tuple<T1, T2>, TResult> _dataCache = new ConcurrentDictionary<Tuple<T1, T2>, TResult>();
public TResult GetCacheableValue(T1 arg1, T2 arg2)
{
TResult returnValue;
var key = Tuple.Create(arg1, arg2);
if (!_dataCache.TryGetValue(key, out returnValue))
{
lock (_syncRoot)
{
if (!_dataCache.TryGetValue(key, out returnValue))
{
returnValue = _retrievalFunc(arg1, arg2);
_dataCache[key] = returnValue;
}
}
}
return returnValue;
}
public ReturnCacheInternal(Func<T1, T2, TResult> func)
{
_retrievalFunc = func;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment