我需要将一些信息作为lambda表达式传递给某些方法。基本上,它是一种向数据库查询添加信息的方法。一个简单的例子是:
companyData.GetAll(
where => "SomeField = @SOMEFIELD",
order => "Id",
SOMEFIELD => new Parameter {DbType = DbType.String, Value = "some value"}
)
它工作得很好,除了我需要调用LambdaExpression.Compile来获取参数对象这一事实,这会对性能产生很大的影响。
为了获得更快的结果,我参加了这个天真的缓存测试:
class ExpressionCache<T,U>
{
private static ExpressionCache<T, U> instance;
public static ExpressionCache<T, U> Instance
{
get
{
if (instance == null) {
instance = new ExpressionCache<T, U>();
}
return instance;
}
}
private ExpressionCache() { }
private Dictionary<string, Func<T, U>> cache = new Dictionary<string, Func<T, U>>();
public Func<T, U> Get(Expression<Func<T, U>> expression)
{
string key = expression.Body.ToString();
Func<T,U> func;
if (cache.TryGetValue(key, out func)) {
return func;
}
func = expression.Compile();
cache.Add(key, func);
return func;
}
}
这个类产生了巨大的差异:从10000次迭代的大约35000毫秒到大约700次。
现在出现了一个问题:我将使用表达式body作为字典的键来遇到什么样的问题?
答案 0 :(得分:10)
Lambda表达式可以创建闭包。当发生这种情况时,表达式主体不包含进入结果代码的所有内容。您可能会遗漏包含的潜在重要局部变量。
答案 1 :(得分:10)
我不清楚为什么你需要表达树,如果你正在将它们编译成代表。为什么不直接使用委托开始并让编译器将lambda表达式转换为委托而不是表达式树?
至于使用字符串的主体 - 你可能会遇到奇怪的情况,你使用不同的类型,但使用相同的属性名称。鉴于您已经将类型用作泛型类型参数,但这可能不是问题...我认为它会起作用,尽管我想发誓。
哦,顺便说一句,你的单例缓存不是线程安全的。我建议您在静态初始化程序中初始化instance
变量。这样可以使代码更简单,也更安全......
private static readonly ExpressionCache<T, U> instance
= new ExpressionCache<T, U>();
public static ExpressionCache<T, U> Instance { get { return instance; } }