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
WeakCacheFormethod 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.
I don’t see any point in using a weak reference. Once you have loaded the data there is hardly any reason to throw it away until you are sure that it’s not useful any more.
What you are implementing is a variation of the lazy loading pattern. Stick to the simple pattern and just use a regular reference to the item:
(And a small tip: You are using the
varkeyword way too much.)