views:

73

answers:

2

I've always wondered about when and where is the best time to cache a property value... Some of them seem pretty simple, like the one below...

public DateTime FirstRequest {
    get {
        if (this.m_FirstRequest == null) {
            this.m_FirstRequest = DateTime.Now;
        }
        return (DateTime)this.m_FirstRequest;
    }
}
private DateTime? m_FirstRequest;

But what about some more complicated situations?

  1. A value that comes from a database, but remains true after it's been selected.
  2. A value that is stored in a built-in cache and might expire from time to time.
  3. A value that has to be calculated first?
  4. A value that requires some time to initialize. 0.001s, 0.1s, 1s, 5s???
  5. A value that is set, but something else may come and set it to null to flag that it should be repopulated.
  6. ??? There seems to be limitless situations.

What do you think is the point that a property can no longer take care of itself and instead require something to populate its value?


[EDIT]

I see suggestions that I'm optimizing too early, etc. But my question is for when it is time to optimize. Caching everything isn't what I'm asking, but when it is time to cache, whose responsibility should it be?

A: 

I think you need to turn your question the other way around lest you fall into a trap of optimizing too early.

When do you think is the point that a property no longer needs recalculating on every call and instead uses some form of caching?

The caching of a value is an optimization and should therefore not be done as the norm. There are some cases where it is clearly relevant to use this optimization but in most cases, you should implement the property to work correctly every time by doing the appropriate work to get the value and then look to optimize it once you've profiled and shown that optimization is required.

Some reasons why caching is or is not a good idea: - Don't cache if the value is prone to frequent change - Do cache if it never changes and you are responsible for it never changing - Don't cache if you are not responsible for providing the value as you're then relying on someone else's implementation

There are many other reasons for and against caching a value but there is certainly no hard and fast rule on when to cache and when not to cache - each case is different.

If you have to cache...

Assuming that you've determined some form of caching is the way to go, then how you perform that caching depends on what you are caching, why, and how the value is provided to you.

For example, if it is a singleton object or a timestamp as in your example, a simple "is it set?" condition that sets the value once is a valid approach (that or create the instance during construction). However, if it's hitting a database and the database tells you when it changes, you could cache the value based on a dirty flag that gets dirtied whenever the database value says it has changed. Of course, if you have no notification of changes, then you may have to either refresh the value on every call, or introduce a minimum wait time between retrievals (accepting that the value may not always be exact, of course).

Whatever the situation, you should always consider the pros and cons of each approach and consider the scenarios under which the value is referenced. Do the consumers always need the most recent value or can they cope with being slightly behind? Are you in control of the value's source? Does the source provide notification of changes (or can you make it provide such notifications)? What is the reliability of the source? There are many factors that can affect your approach.

Considering the scenarios you gave...

Again, assuming that caching is needed.

  1. A value that comes from a database, but remains true after it's been selected.
    If the database is guaranteed to retain that behavior, you can just poll the value the first time it is requested and cache it thereafter. If you can't guarantee the behavior of the database, you may want to be more careful.

  2. A value that is stored in a built-in cache and might expire from time to time.
    I would use a dirty flag approach where the cache is marked dirty from time to time to indicate that the cached value needs refreshing, assuming that you know when "time to time" is. If you don't, consider a timer that indicates the cache is dirty at regular intervals.

  3. A value that has to be calculated first?
    I would judge this based on the value. Even if you think caching is needed, the compiler may have optimised it already. However, assuming caching is needed, if the calculation is lengthy, it might be better during construction or via an interface such as ISupportInitialize.

  4. A value that requires some time to initialize. 0.001s, 0.1s, 1s, 5s???
    I'd have the property do no calculation for this and implement an event that indicates when the value changes (this is a useful approach in any situation where the value might change). Once the initialization is complete, the event fires, allowing consumers to get the value. You should also consider that this might not be suited for a property; instead, consider an asynchronous approach such as a method with a callback.

  5. A value that is set, but something else may come and set it to null to flag that it should be repopulated.
    This is just a special case of the dirty flag approach discussed in point 2.

Jeff Yates
I understand what you're saying, but this I'm asking in reference to properties that should be cached. I won't cache anything unless I need to (for example, hitting a database for information that won't change often)
Hugoware
Okay, I've updated my answer to take that into account.
Jeff Yates
+1  A: 

In general, you should get the code working first and then optimize later and then only do optimizations that profiling say will help you.

David Norman