如何从我的漂亮缓存扩展的lambda表达式中获取参数值?

时间:2010-08-20 00:10:54

标签: asp.net caching lambda

首先,值得看看这个问题: How can I cache objects in ASP.NET MVC?

有些伪代码几乎可以满足我的需求:

public class CacheExtensions
{
  public static T GetOrStore<T>(this Cache cache, string key, Func<T> generator)
  {
    var result = cache[key];
    if(result == null)
    {
      result = generator();
      cache[key] = result;
    }
     return (T)result;
   }
}

然而,我真正想做的是从发生器自动生成“密钥”。我想我需要将方法签名更改为:

public static T GetOrStore<T>(this Cache cache,
                System.Linq.Expressions.Expression<Func<T>> generator)

我想使用方法名称,还要使用任何参数及其值来生成密钥。我可以从表达式和参数名称(类型)中获取方法体,但我不知道如何获取参数值...?

或者我是以错误的方式来做这件事的?任何想法都非常赞赏。

2 个答案:

答案 0 :(得分:0)

当调用生成集合的函数时,我想要缓存我将所有函数的参数和函数名称传递给缓存函数,该函数从中创建密钥。

我的所有类都实现了一个具有ID字段的接口,因此我可以在缓存键中使用它。

我确信有一种更好的方式,但不知怎的,我有时也会睡觉。

我还传递了一个或多个可用于使相关集合无效的关键字。

答案 1 :(得分:0)

我是这样做的:

public static class ICacheExtensions
{
    public static T GetOrAdd<T>(this ICache cache, Expression<Func<T>> getterExp)
    {
        var key = BuildCacheKey<T>(getterExp);
        return cache.GetOrAdd(key, () => getterExp.Compile().Invoke());
    }

    private static string BuildCacheKey<T>(Expression<Func<T>> getterExp)
    {
        var body = getterExp.Body;
        var methodCall = body as MethodCallExpression;
        if (methodCall == null)
        {
            throw new NotSupportedException("The getterExp must be a MethodCallExpression");
        }

        var typeName = methodCall.Method.DeclaringType.FullName;
        var methodName = methodCall.Method.Name;
        var arguments = methodCall.Arguments
            .Select(a => ExpressionHelper.Evaluate(a))
            .ToArray();

        return String.Format("{0}_{1}_{2}", 
            typeName, 
            methodName, 
            String.Join("|", arguments));
    }
  }

使用此帮助程序来评估表达式树的节点:

internal static class ExpressionHelper
    {
        public static object Evaluate(Expression e)
        {
            Type type = e.Type;
            if (e.NodeType == ExpressionType.Convert)
            {
                var u = (UnaryExpression)e;
                if (TypeHelper.GetNonNullableType(u.Operand.Type) == TypeHelper.GetNonNullableType(type))
                {
                    e = ((UnaryExpression)e).Operand;
                }
            }
            if (e.NodeType == ExpressionType.Constant)
            {
                if (e.Type == type)
                {
                    return ((ConstantExpression)e).Value;
                }
                else if (TypeHelper.GetNonNullableType(e.Type) == TypeHelper.GetNonNullableType(type))
                {
                    return ((ConstantExpression)e).Value;
                }
            }
            var me = e as MemberExpression;
            if (me != null)
            {
                var ce = me.Expression as ConstantExpression;
                if (ce != null)
                {
                    return me.Member.GetValue(ce.Value);
                }
            }
            if (type.IsValueType)
            {
                e = Expression.Convert(e, typeof(object));
            }
            Expression<Func<object>> lambda = Expression.Lambda<Func<object>>(e);
            Func<object> fn = lambda.Compile();
            return fn();
        }
    }