I have the following data structure:
class OrderLine : Table
{
public int Id { get; set; }
public Order Order { get; set; }
public decimal Quantity { get; set; }
public decimal UnitPrice { get; set; }
[CalculatedField]
public decimal LinePrice {
get => Quantity * LinePrice;
}
}
I want to traverse the Expression of the LinePrice getter with an ExpressionVisitor. To build a request to a remote system.
Is there a way to (via reflection?) to access the expression bodied member getter's Expression?
CodePudding user response:
You cannot traverse the Expression
of expression-bodied properties, because they are not Expression
objects. Expression-bodied properties are no different from other properties, except their syntax. Your property here:
public decimal LinePrice {
get => Quantity * LinePrice; // did you mean UnitPrice?
}
is compiled into: (as is seen on SharpLab)
.method public hidebysig specialname
instance valuetype [System.Private.CoreLib]System.Decimal get_LinePrice () cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance valuetype [System.Private.CoreLib]System.Decimal OrderLine::get_Quantity()
IL_0006: ldarg.0
IL_0007: call instance valuetype [System.Private.CoreLib]System.Decimal OrderLine::get_LinePrice()
IL_000c: call valuetype [System.Private.CoreLib]System.Decimal [System.Private.CoreLib]System.Decimal::op_Multiply(valuetype [System.Private.CoreLib]System.Decimal, valuetype [System.Private.CoreLib]System.Decimal)
IL_0011: ret
}
which is the same code that would be generated, if you used a block-bodied property. And as you can see, there's no Expression
s anywhere. You can try this on SharpLab. This shows that expression-bodied members are purely syntactic sugar.
If you want to traverse it as an Expression
, you should actually declare an Expression
:
// now you can traverse this with ExpressionVisitor
public static readonly Expression<Func<OrderLine, decimal>> LinePriceExpression
= x => x.Quantity * x.UnitPrice;
// to avoid repeating "Quantity * UnitPrice" again in the property getter,
// you can compile the expression and reuse it
private static readonly Func<OrderLine, decimal> LinePriceExpressionCompiled
= LinePriceExpression.Compile();
public decimal LinePrice => LinePriceExpressionCompiled(this);