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.