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

发布于 2024-09-15 08:52:52 字数 792 浏览 3 评论 0原文

首先,这个问题可能值得一看: 如何在 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)

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

或者我以错误的方式处理这个问题?任何想法都非常感激。

First of all it might be worth looking at this question:
How can I cache objects in ASP.NET MVC?

There some pseudo code that almost does what i want:

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;
   }
}

However, what I'd really like to do, is auto-generate the "key" from the generator. I figure i need to change the method signature to:

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

I want to use the method name, but also any parameters and their values to generate the key. I can get the method body from the expression, and the paramter names (sort of), but I have no idea how to get the paramter values...?

Or am I going about this the wrong way? Any ideas much appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

∞梦里开花 2024-09-22 08:52:52

我是这样做的:

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();
        }
    }

Here's how I did it:

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));
    }
  }

with this helper to evaluate nodes of an expression tree:

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();
        }
    }
一百个冬季 2024-09-22 08:52:52

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

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

我确信有更好的方法,但不知怎的,我有时也得睡觉。

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

When calling a function that produces a collection i want to cache i pass all my function's parameters and function name to the cache function which creates a key from it.

All my classes implement an interface that has and ID field so i can use it in my cache keys.

I'm sure there's a nicer way but somehow i gotta sleep at times too.

I also pass 1 or more keywords that i can use to invalidate related collections.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文