6
\$\begingroup\$

Are there issues of any kind with this extension method?

using System;
using System.Web;

namespace AccountingBackupWeb.CacheExtensions
{
    public static class Extensions
    {
        public static T Get<T>(this System.Web.Caching.Cache cache, string key, Func<T> f) where T : class
        {
            T results = HttpContext.Current.Cache[key] as T;

            if (results == null)
            {
                results = f();
                HttpContext.Current.Cache[key] = results;
            }

            return results;
        }
    }
}
\$\endgroup\$
4
  • 3
    \$\begingroup\$ Why do you have cache as the first parameter when you don't use it in the method at all? \$\endgroup\$ Dec 15, 2011 at 21:25
  • \$\begingroup\$ the only reason is so that it is an extension method as opposed to a static utility function.. good point though \$\endgroup\$ Dec 15, 2011 at 22:07
  • 3
    \$\begingroup\$ but if you are not actually doing anything with "cache" why should this be an extension method on that type? \$\endgroup\$ Dec 16, 2011 at 8:59
  • \$\begingroup\$ ah, it took me a minute, but your saying make the first line of the implementation T results = cache[key] as T, right? \$\endgroup\$ Dec 16, 2011 at 16:01

7 Answers 7

4
\$\begingroup\$

Logically, it makes sense to me that you would want to tie a key to a Func. This method could then just take the string and then delegate the responsibility to decide how to fetch the value to another class. Also, a few nitpicky points about what is actually there. I consider using letters as variables poor practice since it gives no context as to how it will be used. I would rename "f" to something like "retrieve" or "fetch". Also, there is no guarantee that running "f" will actually give you a non null value. In that case, I doubt you would want to store null in your cache.

\$\endgroup\$
0
3
\$\begingroup\$

Without some more context on what your goals and/or concerns are its hard to say. This seem ok, although passing delegate functions is relatively expensive so if hyper-performance is required, you should refactor that. Aside from that, the only issue may be HttpContext.Current being null which would cause a NullReferenceException, although I assume this is not possible given your hosting scenario.

\$\endgroup\$
0
1
\$\begingroup\$

As JoeGeeky said HttpContext.Current might be null and it is better to ckeck it. But I also want to point out that from architectural point of view it is always better to incapsulate your cache host (HttpContext.Current in your case), so your framework cache getter method won't depend on Web classes.

You can introduce an abstract class (or interface) CacheHost and on runtime configure which actual subclass will be used as cache host. In most of your cases it could be HttpContext.Current, but if you run a separate thread and there you will use methods that relies on your cache, then you will be able to leverage your cache mechanism even if there is no HttpContext.Current in that thread.

\$\endgroup\$
1
\$\begingroup\$

I just have a little issue with the method name itself. It's not given by the name of a method called "Get" that it actually sets the cache value to the result of f if not already set, and then returns it. How 'bout GetOrInitializeTo, and then having a Get method that just gets?

\$\endgroup\$
1
\$\begingroup\$

In addition to what's already been said:

  • the key parameter might be null
  • the f parameter might be null
  • The mechanism is highly inefficient if you actually want to cache null for a specific key
\$\endgroup\$
1
\$\begingroup\$

Since the as T operation will result in null if the value is actually not null but is not of type T, you might consider doing an extra check when results is null to determine whether the value in cache at that key is actually null. Example implementation shown below:

    public static T Get<T>(this System.Web.Caching.Cache cache, string key, Func<T> f) where T : class
    {
        object value = cache[key];

        T results = value as T;

        if (results == null)
        {
            if (value != null)
            {
                // log a warning, because there is a non-null value in cache with this key, but it is not of the specified type.
            }

            results = f();
            cache[key] = results;
        }

        return results;
    }

Essentially, if results is null but value is not null, then that means that there is already some value in cache with the specified key that is not of type T. I would consider that situation a potential coding error, so I would most likely want to log a warning or an error if that were to happen.

Alternatively, you could throw an exception. That would allow you to keep the details of your logging mechanism out of this utility method.

\$\endgroup\$
0
\$\begingroup\$

Use var when the right-hand side of a declaration makes its type obvious:

T results = HttpContext.Current.Cache[key] as T;

Should be

var results = HttpContext.Current.Cache[key] as T;

Here, the as T clause makes it very obvious that results is of type T. Using var means that changing T becomes a single operation, as opposed to changing it in two places.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.