Skip to content

Instantly share code, notes, and snippets.

@atheken
Created November 4, 2012 22:15
Show Gist options
  • Save atheken/4014001 to your computer and use it in GitHub Desktop.
Save atheken/4014001 to your computer and use it in GitHub Desktop.
A lazy, but not too lazy, memoization class.
using System;
namespace BlogUtils
{
/// <summary>
/// An extension of "Lazy of T, but with the twist that it will
/// reload the resource at periodic intervals (and on request, of course).
/// </summary>
public class LazyEnough<T>
{
private Func<T> _loader;
private DateTime _lastLoaded = DateTime.MinValue;
private Lazy<T> _lazyLoad;
private TimeSpan _reloadInterval;
public LazyEnough (Func<T> loader) : this(loader, new TimeSpan(0,0,1,0,0))
{
}
public LazyEnough (Func<T> loader, TimeSpan reloadInterval)
{
_loader = loader;
_lazyLoad = new Lazy<T> (loader);
_reloadInterval = reloadInterval;
}
/// <summary>
/// Return the value, and if the timespan for reload has elapsed, let's refresh and return.
/// </summary>
/// <value>
/// The materialized value.
/// </value>
public T Value {
get {
return this.GetValue ();
}
}
/// <summary>
/// Is this class too lazy for you? You can force it to do some work by calling this method with "forceReload" true.
/// </summary>
/// <returns>
/// The refreshed value.
/// </returns>
public T GetValue (bool forceReload = false)
{
var requestTime = DateTime.Now;
if (forceReload || _lastLoaded + _reloadInterval < requestTime) {
// it's possible that more than one "reload" could be requested and
// running on this line, but that would likely be the case under very high
// contention for this resource, and very short reload intervals.
// We could do fancy locks or interlocked code to avoid absolutely ALL "leaks",
// but here's an example where adding a bunch of code for "performance" ends up
// making maintainability more painful.
_lastLoaded = requestTime;
_lazyLoad = new Lazy<T> (_loader);
}
return _lazyLoad.Value;
}
}
}
public class ExpensiveResourceConsumer
{
/// <summary>
/// A shared instance of the resource for all instances of the consumer.
/// </summary>
private static LazyEnough<ExpensiveResource> _resource;
public ExpensiveResourceConsumer ()
{
// if the resource hasn't been built yet, build it once, yes, this could potentially
// build multiple "LazyEnough<T>" classes, but seriously, object construction is CHEAP,
// and you'll note that it doesn't actually construct the ExpensiveResource.
_resource = _resource ?? new LazyEnough (() => new ExpensiveResource ());
}
private class ExpensiveResource
{
ExpensiveResource ()
{
//Does something expensive to construct itself.
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment