25

I got bored with writing same to code again and again to cache the objects in data access layer.

Is there anyway to cache c# function results without much changes to functions.

Is there any framework supports this functionality at the moment?

Can i archive the same by writing custom "c# function attributes"? if so, drop me some points to start implementation?

2
  • 3
    "I got bored with writing same to code again and again to cache the objects in data access layer. " - Inheritance perhaps? Commented Feb 8, 2011 at 4:30
  • 1
    not Inheritance, don't want to write redundant code to check whether cache object exist or not? and then either make a call to actual object or take from cache. Any way "Yuriy Faktorovich" addressed every nicely. That is what i'm looking for exactly Commented Feb 8, 2011 at 6:17

8 Answers 8

27

Possibility 1: Use IL Weaving

Postsharp was mentioned before.

You could also try the MethodCache.Fody package.

Possibility 2: Use an Proxy / Interception Framework

Example (Ninject & Ninject.Interception):

public class CacheAttribute : InterceptAttribute
{
    public override IInterceptor CreateInterceptor(IProxyRequest request)
    {
        return request.Context.Kernel.Get<CachingInterceptor>();
    }
}

public class CachingInterceptor : IInterceptor
{
    private ICache Cache { get; set; }

    public CachingInterceptor(ICache cache)
    {
        Cache = cache;
    }

    public void Intercept(IInvocation invocation)
    {
        string className = invocation.Request.Target.GetType().FullName;
        string methodName = invocation.Request.Method.Name;

        object[] arguments = invocation.Request.Arguments;

        StringBuilder builder = new StringBuilder(100);
        builder.Append(className);
        builder.Append(".");
        builder.Append(methodName);

        arguments.ToList().ForEach(x =>
        {
            builder.Append("_");
            builder.Append(x);
        });

        string cacheKey = builder.ToString();

        object retrieve = Cache.Retrieve<object>(cacheKey);

        if (retrieve == null)
        {
            invocation.Proceed();
            retrieve = invocation.ReturnValue;
            Cache.Store(cacheKey, retrieve);
        }
        else
        {
            invocation.ReturnValue = retrieve;
        }
    }
}

Then you could decorate functions like this:

[Cache]
public virtual Customer GetCustomerByID(int customerID)
{
    return CustomerRepository.GetCustomerByID(customerID);
}

Intercepted functions have to be virtual and classes must be created by the Ninject kernel. If you rely on performance, you could proxy classes directly via Castle.DynamicProxy (which is internally used by Ninject.Extensions.Interception.DynamicProxy).

Possibility 3: Use an Expression wrapper

You could pass the function as expression, generate a caching key containing class, method and parameter information and invoke the expression if not found in your Cache. This adds more runtime overhead than AOP / Proxy frameworks, but will be sufficient for simple solutions.

private T CacheAction<T>(Expression<Func<T>> action, [CallerMemberName] string memberName = "") where T : class
{
    MethodCallExpression body = (MethodCallExpression)action.Body;

    ICollection<object> parameters = new List<object>();

    foreach (MemberExpression expression in body.Arguments)
    {
        parameters.Add(((FieldInfo)expression.Member).GetValue(((ConstantExpression)expression.Expression).Value));
    }

    StringBuilder builder = new StringBuilder(100);
    builder.Append(GetType().FullName);
    builder.Append(".");
    builder.Append(memberName);

    parameters.ToList().ForEach(x =>
    {
        builder.Append("_");
        builder.Append(x);
    });

    string cacheKey = builder.ToString();

    T retrieve = Cache.Retrieve<T>(cacheKey);

    if (retrieve == null)
    {
        retrieve = action.Compile().Invoke();
        Cache.Store(cacheKey, retrieve);
    }

    return retrieve;
}

public Customer GetCustomerByID(int customerID)
{
    return CacheAction(() => CustomerRepository.GetCustomerByID(customerID));
}
Sign up to request clarification or add additional context in comments.

3 Comments

I like the third option, this way I can control whenever the method must be cached or not (passing a boolean attribute)
What is Cache class? There is MemoryCache but it does not have Retrieve and Store methods. Next time please include full implementation.
The question was not about cache implementations but how to reduce the boiler plate code of caching and retrieving objects. That's what my answer provide. It should be clear that you have to replace Cache (and Retrieve / Store) with the concrete implementations of the cache framework of your choice.
7

You can create caching attributes with PostSharp. You can use the Cache attribute.

3 Comments

The second link is not working, consider adding some explanation in the answer.
You can also read excellent article here phillipsj.net/posts/dotnet-method-caching
@rafalkasa in retrospect the entire concept seems convenient but not very OO/unit test friendly. Better to inject a service and let the methods handle caching granularly. In general, obviously in some cases this may be better.
7

If I read you question correct, the right term for what you want is memoization. Wikipedia gives more details on this subjects. Unfortunately there is no reference to a C# library supporting it.

Comments

5

Lazy store it's value after first run. Example: http://msdn.microsoft.com/en-us/vstudio/bb870976

Comments

3

I use this simple implementation of the System.Runetime.Caching namespace:

public class InMemoryCache : ICacheService
{
    public T GetOrSet<T>(string cacheKey, Func<T> getItemCallback) where T : class
    {
        T item = MemoryCache.Default.Get(cacheKey) as T;
        if (item == null)
        {
            item = getItemCallback();
            MemoryCache.Default.Add(cacheKey, item, DateTime.Now.AddHours(4));
        }
        return item;
    }

    public void Clear(string cacheKey)
    {
        MemoryCache.Default.Remove(cacheKey);
    }
}

interface ICacheService
{
    T GetOrSet<T>(string cacheKey, Func<T> getItemCallback) where T : class;
    void Clear(string cacheKey);
}

Can be used in the following manner:

var cacheProvider = new InMemoryCache();
var cachedResult = cacheProvider.GetOrSet("YourCacheKey",
                () => MethodToCache());

First call to the method will cache the result, the next call will return the cached result.

1 Comment

Thank you, for that brief and great implementation!
2

The Cache Application block is Microsoft's answer to built in library for Caching in .NET.

1 Comment

Note that as of Enterprise Library 6, the block was retired (see msdn.microsoft.com/en-us/library/dn169621.aspx). That's understandable as the functionality can be found in System.Runtime.Caching since .NET 4.0 (see msdn.microsoft.com/en-us/library/…).
0

I suggest Spring.Net AOP. It basically creates a proxy and the calls can be redirected from/to the cache. http://www.springframework.net/doc/reference/html/aop-quickstart.html

and then you can have something like that for your advice:

public class CachingAroundAdvice : IMethodInterceptor
{
    #region Variable Declarations
    private Priority priority = Priority.Normal;
    #endregion

    public object Invoke(IMethodInvocation invocation)
    {
        // declare local variables
        string cacheKey = string.Empty;
        object dataObject = null;

        // build cache key with some algorithm
        cacheKey = CreateCacheKey(invocation.Method, invocation.Arguments);

        // retrieve item from cache
        dataObject = CacheManager.Cache.GetData(cacheKey);

        // if the dataobject is not in cache proceed to retrieve it
        if (null == dataObject)
        {
            dataObject = invocation.Proceed();

            // add item to cache
            CacheManager.Cache.Add(cacheKey, dataObject, CachePriority, null, Expiration);
        }

        // return data object
        return dataObject;
    }

Comments

0

You could use a Dictionary to cache the function. A dictionary maps keys to values and a function maps arguments to values. So conceptually, a dictionary fits as a cache for a function. Here's a simple class to do that:

/// <summary>
/// The lazy function map caches the results of calls to the backing function. Every time the function is called on an argument u and returns v,
/// the pair (u, v) is stored in the dictionary.
/// </summary>
class LazyFunctionMapImpl<T, U> : ILazyFunctionMap<T, U>
{
    private readonly Dictionary<T, U> _backingDictionary;
    private readonly Func<T, U> _backingFunction;

    public LazyFunctionMapImpl(Func<T, U> backingFunction)
    {
        _backingDictionary = new Dictionary<T, U>();
        _backingFunction = backingFunction;
    }

    public U this[T index]
    {
        get
        {
            if (_backingDictionary.ContainsKey(index))
            {                    
                return _backingDictionary[index];
            }                
            U valueAtIndex = _backingFunction(index);
            _backingDictionary.Add(index, valueAtIndex);
            return valueAtIndex;
        }
    }

    public void Clear()
    {
        _backingDictionary.Clear();
    }
}

And here's a couple of interfaces to go with it:

/// <summary>
/// A function map that should lazily cache param/result pairs until clear is called.
/// </summary>    
public interface ILazyFunctionMap<T, U> : IFunctionMap<T, U>
{
    /// <summary>
    /// Should invalidate any caches forcing the underyling function to be called afresh
    /// </summary>
    void Clear();
}

public interface IFunctionMap<T, U>
{
    /// <summary>
    /// Mapped values representing the underlying function.
    /// </summary>
    U this[T index] { get; }
}

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.