这完全与Compile
类型的Expression
方法有关。抱歉天真,因为我是后来者。我一直在阅读有关构建表达式的信息,以便动态修改可执行代码。对于我来说,只要对于不同的输入/环境(例如对于任何给定的常量/参数/成员表达式的不同值),从给定的表达式树中发出lambda表达式对我来说是有意义的。我认为,如果我可以缓存(重复使用)lambda那些是从表达式树生成/编译的,只要环境没有变化,那将是理想的。
问题:即使环境没有变化,CLR是否总是发出lambda表达式?如果是这样,那么如果环境没有变化,最好避免从lambda编译表达式?
答案 0 :(得分:3)
每次返回新的委托时,CLR都不会缓存lambda表达式Compile()
。
但通过以下方式缓存应该很容易:
public Func<T> Get<T>(Expression<Func<T>> expression)
{
string key = expression.Body.ToString();
Func<T> result;
if (!_cache.TryGetValue(key, out result)) {
result = expression.Compile();
_cache.Add(key, result);
}
return result;
}
答案 1 :(得分:2)
Lambda表达式只是表示一段代码的一种方式:调用它,调用它,比较这些参数,返回一些东西等。几乎与从代码编辑器执行它的方式相同,或者JIT从IL执行它。
Compile
从特定的lambda表达式发出委托。一旦你将lambda编译成委托,代理保持不变(lambda也保持不变,因为它是不可变的)。
这并不意味着,该委托不能接受任何参数或调用任何对象的任何方法。这只是意味着,代表的IL不会改变。是的,您可以缓存已编译的委托实例。
答案 2 :(得分:0)
每次调用Compile()
都会返回一个新的委托,每次都会发出新的MSIL代码。这很慢并且有效地创建了内存泄漏,因为MSIL代码不受垃圾回收的影响。我创建了一个提供缓存编译的库,它实际上正确地比较了表达式的结构,并允许重用缓存的委托。所有常量和闭包都会自动替换为参数,并在外部闭包中重新插入到委托中。这可以避免泄漏内存并且速度更快。请在此处查看:https://github.com/Miaplaza/expression-utils