Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I specify the object to return from an expression tree method?

Tags:

I'm trying to create a method using an expression tree that returns an object, but I can't figure out how to actually specify the object to return. I've tried reading this, but the return value doesn't actually seem to be specified anywhere.

I've got all the assignments & stuff down, but how do I specify the object to return from a method created using expression trees?

EDIT: these are v4 expression trees, and the method I'm trying to create does something like this:

private object ReadStruct(BinaryReader reader) {     StructType obj = new StructType();     obj.Field1 = reader.ReadSomething();     obj.Field2 = reader.ReadSomething();     //...more...     return obj; } 
like image 759
thecoop Avatar asked Feb 07 '11 17:02

thecoop


People also ask

What is an expression that returns a value?

In programming languages expression is a unit of code which returns a value. A function call with return value is an expression - it returns value; an integer (or bool or address) literal is also an expression - it has the value of its integer type and so on.

How does an expression tree work?

Expression trees represent code in a tree-like data structure, where each node is an expression, for example, a method call or a binary operation such as x < y . You can compile and run code represented by expression trees.

What is expression tree with example?

Each node in an expression tree is an expression. For example, an expression tree can be used to represent mathematical formula x < y where x, < and y will be represented as an expression and arranged in the tree like structure. Expression tree is an in-memory representation of a lambda expression.

What is expression trees and how they used in LINQ?

Expression Trees provide richer interaction with the arguments that are functions. You write function arguments, typically using Lambda Expressions, when you create LINQ queries. In a typical LINQ query, those function arguments are transformed into a delegate the compiler creates.


2 Answers

There is a much easier way to do this in cases that return an existing parameter or variable. The last statement in a Block Expression becomes the return value. You can include the ParameterExpression again at the end to have it returned.

Assuming your struct is like this:

public struct StructType {     public byte Field1;     public short Field2; } 

Then your code would look like this:

var readerType = typeof(BinaryReader); var structType = typeof(StructType); var readerParam = Expression.Parameter(readerType); var structVar = Expression.Variable(structType);  var expressions = new List<Expression>();  expressions.Add(     Expression.Assign(         Expression.MakeMemberAccess(structVar, structType.GetField("Field1")),         Expression.Call(readerParam, readerType.GetMethod("ReadByte"))         )     );  expressions.Add(     Expression.Assign(         Expression.MakeMemberAccess(structVar, structType.GetField("Field2")),         Expression.Call(readerParam, readerType.GetMethod("ReadInt16"))         )     );  expressions.Add(structVar); //This is the key. This will be the return value.  var ReadStruct = Expression.Lambda<Func<BinaryReader, StructType>>(     Expression.Block(new[] {structVar}, expressions),     readerParam).Compile(); 

Test that it works:

var stream = new MemoryStream(new byte[] {0x57, 0x46, 0x07}); var reader = new BinaryReader(stream); var struct1 = ReadStruct(reader); 

It's worth mentioning this example works if StructType is a struct. If it is a class, you just call the constructor and initialize structVar first thing in the BlockExpression.

like image 106
Ben Avatar answered Oct 19 '22 22:10

Ben


Apparently a return is a GotoExpression that you can create with the Expression.Return factory method. You need to create a label at the end to jump to it. Something like this:

// an expression representing the obj variable ParameterExpression objExpression = ...;  LabelTarget returnTarget = Expression.Label(typeof(StructType));  GotoExpression returnExpression = Expression.Return(returnTarget,      objExpression, typeof(StructType));  LabelExpression returnLabel = Expression.Label(returnTarget, defaultValue);  BlockExpression block = Expression.Block(     /* ... variables, all the other lines and... */,     returnExpression,     returnLabel); 

The types of the label target and the goto expression must match. Because the label target has a type, the label expression must have a default value.

like image 39
R. Martinho Fernandes Avatar answered Oct 19 '22 22:10

R. Martinho Fernandes