我正在尝试编写一些神奇的代码来处理可能或不可能的缓存。基本上,这个想法是有一个带有静态方法的 CacheManager 类,它接受一个 Func 作为参数来执行。在静态方法的主体中,它将能够执行该 Func 并使用一个缓存键来缓存结果,该缓存键唯一地标识该 Func 传递的内部结构(具有 0 个或多个参数的匿名方法)。随后使用提供的相同参数调用该静态方法将产生相同的缓存键并返回缓存结果。
我需要一种唯一标识传入的匿名函数的方法。
编辑:一旦我调整了匿名函数语法,表达式就提供了答案。
我担心必须在运行时编译表达式对性能的影响。鉴于这是一种支持缓存性能的尝试,编译花费任何大量时间都是愚蠢的。有什么想法吗?
用于测试的基本存储库:
public class Product
{
public int ID { get; set; }
public string Name { get; set; }
}
public class ProductRepository
{
private List<Product> products { get; set; }
public ProductRepository()
{
products = new List<Product>() { new Product() { ID = 1, Name = "Blue Lightsaber" }, new Product() { ID = 2, Name = "Green Lightsaber" }, new Product() { ID = 3, Name = "Red Lightsaber" } };
}
public Product GetByID(int productID)
{
return products.SingleOrDefault(p => p.ID == productID);
}
}
缓存管理器:
public class CacheManager
{
public static TResult Get<TResult>(Expression<Func<TResult>> factory)
{
if (factory == null) throw new ArgumentNullException("factory");
var methodCallExpression = factory.Body as MethodCallExpression;
if (methodCallExpression == null) throw new ArgumentException("factory must contain a single MethodCallExpression.");
string cacheKey = "|Repository:" + methodCallExpression.Method.DeclaringType.FullName + "|Method:" + methodCallExpression.Method.Name + "|Args";
foreach (var arg in methodCallExpression.Arguments)
{
cacheKey += ":" + (arg is ConstantExpression ? ((ConstantExpression)arg).Value : Expression.Lambda(arg).Compile().DynamicInvoke());
}
if (HttpContext.Current.Cache[cacheKey] == null)
{
HttpContext.Current.Cache[cacheKey] = factory.Compile().Invoke();
}
return (TResult)HttpContext.Current.Cache[cacheKey];
}
}
用法:
ProductRepository productRepository = new ProductRepository();
int productID = 1;
Product product;
// From repo
product = CacheManager.Get<Product>(() => productRepository.GetByID(1));
// From cache
product = CacheManager.Get<Product>(() => productRepository.GetByID(productID));