Могу ли я пройти через элемент с телом выражения с помощью ExpressionVisitor?

#c# #linq #expression #expression-trees

Вопрос:

У меня есть следующая структура данных:

 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;
    }
}
 

Я хочу просмотреть выражение получателя строки с помощью ExpressionVisitor. Для создания запроса к удаленной системе.

Есть ли способ (через отражение?) чтобы получить доступ к выражению геттера члена с телом выражения?

Комментарии:

1. Нет, члены с выражениями являются только синтаксическим сахаром.

2. Можете ли вы предоставить документацию, подтверждающую ваше заявление, и опубликовать ее в качестве ответа? Я с радостью приму это как ответ!

Ответ №1:

Вы не можете перейти к свойствам, содержащим выражения, потому что они не являются объектами. Expression Expression Свойства, содержащие выражения, ничем не отличаются от других свойств, за исключением их синтаксиса. Ваша собственность здесь:

 public decimal LinePrice {
    get => Quantity * LinePrice; // did you mean UnitPrice?
}
 

скомпилирован в: (как видно на 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
}
 

это тот же код, который был бы сгенерирован, если бы вы использовали свойство с блочным корпусом. И, как вы можете видеть, нигде нет Expression буквы «с». Вы можете попробовать это на SharpLab. Это показывает, что члены, содержащие выражения, являются чисто синтаксическим сахаром.

Если вы хотите пересечь его как an Expression , вы должны фактически объявить 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);
 

Комментарии:

1. Спасибо за этот замечательный ответ. Это отвечает на мой вопрос и предоставляет достойную альтернативу!