首先,值得看看这个问题: 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)
我想使用方法名称,还要使用任何参数及其值来生成密钥。我可以从表达式和参数名称(类型)中获取方法体,但我不知道如何获取参数值...?
或者我是以错误的方式来做这件事的?任何想法都非常赞赏。
答案 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();
}
}