I've tentatively written this method:
public static Func<T> WeakCacheFor<T>( Func<T> provider ) where T: class
{
var cache = new WeakReference(null);
return () => {
var x = (T)cache.Target;
if( x == null )
{
x = provider();
cache.Target = x;
}
return x;
};
}
So a bit of background:
I have some long-winded legacy methods which look a bit like this:
var id = GetDatabaseId();
if(a){
var data = GetLoader().Init(id).GetData(); // expensive!
// do stuff with data
}
if(b){
// don't load data
}
... lots more variations, some contain GetLoader().Init(id).GetData(); some don't....
My potential solution is to do this:
var id = GetDatabaseId();
var loadData = WeakCacheFor(() => GetLoader().Init(id).GetData());
if(a){
var data = loadData();
// do stuff with data
}
if(b){
// don't load data
}
... lots more variations, some contain loadData(); some don't....
My thoughts about this:
- I don't need to cache beyond the scope of this method call, so it's fine if the GC collects it as soon as the method returns
- If the code takes a path which doesn't need to load the data, the hit won't be incurred
- If it does need the data it will be cached in the weak reference if it's needed again.
- If the GC does collect midway, it won't matter as it will just get re-loaded.
My questions:
- Will this actually work? - Is there anything that I've missed in the
WeakCacheFor
method that might cause a strong reference to inadvertenly be held? - Am I being too clever for my own good? - Should I just incur the hit and cache the data in a normal local variable even if it's not needed?
I suspect I may be being too clever, but even if I am, does this seem to anyone else like a solution which can be usefully applied in other situations??
Update: Modified function because apparently you can't trust .IsAlive
Update: I realized that the returned Func
will go out of scope at the end of the method, so I don't need a weakref at all and a normal ref will work just fine. I Was suffering from a case of "can't see the forest for the trees" I think.