无论如何在C#中缓存函数/方法

Vee*_*eru 15 .net c#

我厌倦了一次又一次地写代码来缓存数据访问层中的对象.

无论如何都要缓存c#函数结果而不需要对函数进行太多更改.

目前是否有任何框架支持此功能?

我可以通过编写自定义"c#函数属性"来存档吗?如果是这样,请给我一些积分来开始实施?

Dre*_*sel 23

可能性1:使用IL编织

之前提到过Postsharp.

您也可以尝试MethodCache.Fody包.

可能性2:使用代理/拦截框架

示例(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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以装饰这样的函数:

[Cache]
public virtual Customer GetCustomerByID(int customerID)
{
    return CustomerRepository.GetCustomerByID(customerID);
}
Run Code Online (Sandbox Code Playgroud)

截获的函数必须是虚函数,并且必须由Ninject内核创建类.如果依赖性能,可以直接通过Castle.DynamicProxy(Ninject.Extensions.Interception.DynamicProxy在内部使用)代理类.

可能性3:使用表达式包装器

您可以将函数作为表达式传递,生成包含类,方法和参数信息的缓存键,并在缓存中找不到表达式(如果未找到).这比AOP/Proxy框架增加了更多的运行时开销,但对于简单的解决方案来说已足够.

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));
}
Run Code Online (Sandbox Code Playgroud)


Yur*_*ich 6

您可以使用PostSharp创建缓存属性.是一个例子.


mis*_*isl 5

如果我读到您的问题正确,那么您想要的正确术语是备忘录。维基百科提供了有关此主题的更多详细信息。不幸的是,没有引用支持它的C#库。