Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent .NET from "lifting" local variables

Tags:

c#

.net

lambda

I have the following code:

string prefix = "OLD:";
Func<string, string> prependAction = (x => prefix + x);
prefix = "NEW:";
Console.WriteLine(prependAction("brownie"));

Because the compiler replaces the prefix variable with a closure "NEW:brownie" is printed to the console.

Is there an easy way to prevent the compiler from lifting the prefix variable whilst still making use of a lambda expression? I would like a way of making my Func work identically to:

Func<string, string> prependAction = (x => "OLD:" + x);

The reason I need this is I would like to serialize the resulting delegate. If the prefix variable is in a non-serializable class the above function will not serialize.

The only way around this I can see at the moment is to create a new serializable class that stores the string as a member variable and has the string prepend method:

string prefix = "NEW:";
var prepender = new Prepender {Prefix = prefix};
Func<string, string> prependAction = prepender.Prepend;
prefix = "OLD:";
Console.WriteLine(prependAction("brownie"));

With helper class:

[Serializable]
public class Prepender
{
    public string Prefix { get; set; }
    public string Prepend(string str)
    {
        return Prefix + str;
    }
}

This seems like a lot of extra work to get the compiler to be "dumb".

like image 481
Brownie Avatar asked Sep 21 '08 08:09

Brownie


1 Answers

I see the underlying problem now. It is deeper than I first thought. Basically the solution is to modify the expression tree before serializing it, by replacing all subtrees that do not depend on the parameters with constant nodes. This is apparently called "funcletization". There is an explanation of it here.

like image 67
Rasmus Faber Avatar answered Oct 06 '22 06:10

Rasmus Faber