简体   繁体   中英

Expression Tree and Compile method

This is all about the Compile method of Expression Type. Sorry being naïve since I am a late comer. I have been reading about building expression in order to enables dynamic modification of executable code. And It make sense for me when it comes to emitting lambda expression from a given expression tree as long as for the varying inputs/environment (say for different values for any given constant/parameter/member expression). I presume, it would be ideal if I could cache (re-use) lambda those are generated/compiled from an expression tree provided there is no change in the environment.

Question : Does CLR always emit lambda expression even if I have there is no change in the environment? If so, what is the best was to avoid compilation of expression from lambda if there is no change in the environment?

CLR doesn't cache lambda expressions, Compile() each time returns a new delegate.

But it should be easy to cache, via something like this:

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;
}

Lambda expressions is just a way to represent a piece of code: call this, call that, compare these arguments, return something, etc. Almost the same way you do it from code editor, or JIT does from IL.

Compile emits a delegate from particular lambda expression. Once you have compiled lambda into delegate, the delegate remains unchanged (the lambda remains unchanged too, because it is immutable).

This doesn't mean, that delegate can't accept any arguments or call any method of any object. This just means, that delegate's IL doesn't change. And yes, you can cache compiled delegate instance.

Calling Compile() will return a new delegate each time, and each time new MSIL code is emitted. This is slow and effectively creates a memory leak , since MSIL code is not subject to garbage collection. I created a library that offers cached compilation , which in fact compares the structure of the expressions correctly and enables reusing the cached delegates. All constants and closures are automatically replaced by parameters and get re-inserted into the delegate in an outer closure. That avoids the leaking memory and is much faster. Check it out here: https://github.com/Miaplaza/expression-utils

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM