1

这都是关于Type的Compile方法。Expression对不起,因为我迟到了,所以我很天真。我一直在阅读有关构建表达式以启用可执行代码的动态修改的信息。对于我来说,从给定的表达式树发出 lambda 表达式,只要对于不同的输入/环境(例如,对于任何给定的常量/参数/成员表达式的不同值),它都是有意义的。我想,如果我可以缓存(重用)从表达式树生成/编译的 lambda,那将是理想的,前提是环境没有变化。

问题:即使环境没有变化,CLR 是否总是发出 lambda 表达式?如果是这样,如果环境没有变化,最好避免从 lambda 编译表达式?

4

3 回答 3

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;
}
于 2013-06-17T15:34:49.277 回答
2

Lambda 表达式只是表示一段代码的一种方式:调用这个,调用那个,比较这些参数,返回一些东西等。几乎与您在代码编辑器中执行此操作的方式相同,或者 JIT 在 IL 中执行此操作的方式几乎相同。

Compile从特定的 lambda 表达式发出一个委托。将 lambda 编译为委托后,委托保持不变(lambda 也保持不变,因为它是不可变的)。

这并不意味着该委托不能接受任何参数或调用任何对象的任何方法。这只是意味着,该代表的 IL 不会改变。是的,您可以缓存已编译的委托实例。

于 2013-06-17T15:27:29.833 回答
0

每次调用Compile()都会返回一个新的委托,并且每次发出新的 MSIL 代码。这很慢并且有效地造成了内存泄漏,因为 MSIL 代码不受垃圾回收的影响。我创建了一个提供缓存编译的库,它实际上正确地比较了表达式的结构并允许重用缓存的委托。所有常量和闭包都会自动被参数替换,并在外部闭包中重新插入到委托中。这样可以避免内存泄漏并且速度更快。在这里查看:https ://github.com/Miapl​​aza/expression-utils

于 2017-05-18T19:24:37.007 回答