I am working on a project where a few developers decided to use the Caching block in an interesting way.
The code I saw was basically:
if(cache.Contains[MyKey]) return cache.GetData(MyKey); fill cache code....
Contains….hmmm. Sounds innocent, right? You do it with a Dictionary.
This code will work, granted not optimally, but works OK if you always use never-expiring caching. i.e. the default Add. (Of course the scavenger could run between the Contain and GetData and you get screwed) If however you decide to actually use caching with AbsoluteTimeout or SlidingTimeout or other cache timeouts; you get false positives.
Why? Well, the Contains does exactly as you might expect, it see if the key is valid. What it doesn’t do though, is check to see if the cached value is actually expired. Since the scavenger runs only every XX seconds, it is possible your key was expired.
So you do the GetData call on the cache and you get back a null. Gee, why a null? Well, if the cache item was expired, which the GetData enforces before returning, then you get back a null.
So Brian, how should I use the the caching block’s cache manager?
Well, fellow reader, you should use the following. Amazingly simple, eh?
var myValue = cache.GetData(MyKey); if(myValue != null) return myValue; Do fill and add code here............
A lot easier than you expected, and it even works every time. Now, of course you will need to incorporate your own locking strategy around this if you are thread re-entrant.
And yes….GetData is the same as the indexer. cache[MyKey] = cache.GetData[MyKey] Use whatever way you prefer.