Sunday, November 16, 2008

How to serialize Lambda Expressions

At times I need to serialize my Lambda Expressions, to pass to some web service . Normally this wasn't possible but I realized the MetaLinq project allows it. MetaLinq actually grants us modifiable Expression trees. As you might now know Expression Trees are immutable just like strings. Anyway let's serialize and deserialize a Lambda expression within the code:

Expression<Func<int,int>> myLambda = z => z*z ;

// Create a mutable expression, we are using ExpressionBuilder namespace in MetaLinq here
var mutableExpression = ExpressionBuilder.EditableExpression.CreateEditableExpression(myLambda);

// Serialize it
var serializer = new XmlSerializer(typeof(EditableLambdaExpression));
var sw = new StringWriter();
serializer.Serialize(sw, mutableExpression);

// Get the lambda as string, actually sw.ToString() will give us it in string form

var sr = new StringReader(sw.ToString());

var anotherSerializer = new XmlSerializer(typeof(EditableLambdaExpression));

// Deserialize it
var myex = anotherSerializer.Deserialize(sr) as EditableExpression;

// Convert it to lambda expresion

var myNewLambda = myex.ToExpression() as LambdaExpression;

// Invoke it, outputs 16 as expected
Console.Write(myNewLambda.Compile().DynamicInvoke(4));


So this shows us how to convert an expression to string and restore back to expression and invoke it. DynamicInvoke used here since I assumed we don't know the type here. I hope you find it useful

7 comments:

Dosihris said...

Hi,

great blog. Thanks, it works almost great, but i have a small question. The following expression works fine:
Expression[Func[Foo, bool]] func = ((Foo f) => f.Age == 7);

(I have to write normal brakets because the others are not allowed here)

but this one doesn't work. can you help me with that?

int age=7;
Expression[Func[Foo, bool]] func = ((Foo f) => f.Age == age);

Nico

Onur Gümüş said...

Hello Nico,
Unfortunately default implementation of MetaLinq works fully lazily. It means nothing will evaluated at the time of seralization. So deseralization will crash if same local member is not defined in same context. As a workaround you can use this http://emperon.googlepages.com/ExpressionBuilder.dll

This is an experimental modification I made to meta linq that does eager evaluation. It may have some unwanted side effects due to all method calls and member calls are evaluated eagerly.

Anonymous said...

can i use this in an commercial product, where we want to improve our performance? always hard to understand license text! :)

Anonymous said...

Hi,
I worked against your DLL and it seems to work for me. Can you post your code changes somewhere?
Thanks

Stonkie said...

Out of curiosity, how would you go about limiting the priviledges of this lambda? Say I used a lamdba based localization system where my localizable resource file contains serializes lamdbas to format values according to different cultures. How would I prevent someone from injecting malicious code in the ressource files?

Vel said...

Hi,
Thanks for the blog, I am using this ExpressionBuilder for my xmlSerializer, my issue is the after serializing the content has version and culture also, I need version independent so that it can accomodate any future versions of my .net. is there a way I can make this builder version independent?

Regards
Vel

Unknown said...

Hi there,

I realise this post is over 4 years old but I was wondering if there was anything else on offer that might do the same. I am trying to serialise an expression but it contains Generic types and this method fails.

It's of the form: Expression>

Can you think why this might fail? Can you offer any hints at a better method?

cheers,

mat