Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there anyway to cache function/method in C#

Tags:

c#

.net

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?

like image 563
Veeru Avatar asked Feb 08 '11 04:02

Veeru


People also ask

What is Cache method?

How does Caching work? The data in a cache is generally stored in fast access hardware such as RAM (Random-access memory) and may also be used in correlation with a software component. A cache's primary purpose is to increase data retrieval performance by reducing the need to access the underlying slower storage layer.

What is caching in C?

Caching is a separate memory, yes, and it has it's own addresses, but when the CPU caches memory lines from RAM, it keeps a record of what RAM-addresses the memory was on, and keeps a map between RAM-address and cache-address. From the point of view of your program, the address is the same.


6 Answers

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));
}
like image 194
Dresel Avatar answered Oct 04 '22 10:10

Dresel


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

like image 30
Yuriy Faktorovich Avatar answered Oct 04 '22 09:10

Yuriy Faktorovich


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.

like image 43
misl Avatar answered Oct 04 '22 09:10

misl


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

like image 29
ikutsin Avatar answered Oct 04 '22 08:10

ikutsin


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.

like image 45
MichaelCleverly Avatar answered Oct 04 '22 10:10

MichaelCleverly


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

like image 2
George Stocker Avatar answered Oct 04 '22 09:10

George Stocker