Подтвердить что ты не робот

Доступ к значению выражения члена

Если у меня есть продукт.

var p = new Product { Price = 30 };

и у меня есть следующий запрос linq.

var q = repo.Products().Where(x=>x.Price == p.Price).ToList()

В IQueryable провайдере я получаю MemberExpression для p.Price, который содержит константное выражение, однако я не могу получить значение "30" от него.

Обновление Я пробовал это, но он не работает.

var memberExpression = (MemberExpression)GetRootConstantExpression(m);
var fi = (PropertyInfo)memberExpression.Member;
var val = fi.GetValue(((ConstantExpression)memberExpression.Expression).Value, null);

Приветствия.

4b9b3361

Ответ 1

Вы можете скомпилировать и вызвать выражение лямбда, тело которого является доступом к членству:

private object GetValue(MemberExpression member)
{
    var objectMember = Expression.Convert(member, typeof(object));

    var getterLambda = Expression.Lambda<Func<object>>(objectMember);

    var getter = getterLambda.Compile();

    return getter();
}

Локальная оценка является общей методикой при анализе деревьев выражений. LINQ to SQL делает эту точную вещь в нескольких местах.

Ответ 2

 MemberExpression right = (MemberExpression)((BinaryExpression)p.Body).Right;
 Expression.Lambda(right).Compile().DynamicInvoke();

Ответ 3

Постоянное выражение будет указывать на класс захвата, сгенерированный компилятором. Я не включил точки принятия решений и т.д., Но вот как получить 30 от этого:

var p = new Product { Price = 30 };
Expression<Func<Product, bool>> predicate = x => x.Price == p.Price;
BinaryExpression eq = (BinaryExpression)predicate.Body;
MemberExpression productToPrice = (MemberExpression)eq.Right;
MemberExpression captureToProduct = (MemberExpression)productToPrice.Expression;
ConstantExpression captureConst = (ConstantExpression)captureToProduct.Expression;
object product = ((FieldInfo)captureToProduct.Member).GetValue(captureConst.Value);
object price = ((PropertyInfo)productToPrice.Member).GetValue(product, null);

price теперь 30. Обратите внимание, что я предполагаю, что price является свойством, но на самом деле вы должны написать метод GetValue, который обрабатывает свойство/field.

Ответ 4

q имеет тип List<Product>. В списке нет свойства Цена - только отдельные Продукты.

Первый или последний Продукт будет иметь цену.

q.First().Price
q.Last().Price

Если вы знаете, что в коллекции есть только один, вы можете сгладить его, используя Single

q.Single().Price

Ответ 5

Можете ли вы использовать следующее:

var price = p.Price;
var q = repo.Products().Where(x=>x.Price == price).ToList()

Ответ 6

Использование Expression.Lambda(myParameterlessExpression).Compile().Invoke() имеет несколько недостатков:

  • .Compile() работает медленно. Это может занять несколько миллисекунд, даже для небольших фрагментов выражений. Тем не менее, Invoke -call является супер-быстрым, хотя для простых арифметических выражений или доступа членов требуется всего несколько наносекунд.
  • .Compile() будет генерировать (испускать) код MSIL. Это может показаться отличным (и объясняет отличную скорость выполнения), но проблема в том, что этот код занимает память , которая не может быть освобождена до того, как приложение закончит, даже если GC собрал делегат-ссылку!

Можно вообще избегать Compile(), чтобы избежать этих проблем или кэшировать скомпилированные делегаты для повторного использования. Эта небольшая небольшая библиотека предлагает как интерпретацию Expressions, так и кэшированную компиляцию, где все константы и замыкания выражения заменяются дополнительными параметры, которые затем повторно вставлены в закрытие, которое возвращается пользователю. Оба процесса хорошо протестированы, используются в производстве, оба имеют свои плюсы и минусы друг против друга, но намного более 100 раз быстрее, чем Compile() - и избегают утечки памяти!

Ответ 7

И что именно вы пытаетесь достичь?

Поскольку для доступа к значению Price вам нужно сделать что-то вроде:

var valueOfPrice = q[0].Price;

Ответ 8

Если у вас есть класс:

public class Item
{
    public int Id { get; set; }
}

и экземпляр объекта:

var myItem = new Item { Id = 7 };

Вы можете получить значение Id, используя выражение, используя следующий код:

Expression<Func<Item, int>> exp = x => x.Id;
var me = exp.Body as MemberExpression;
var propInfo = me.Member as PropertyInfo;
var value = propInfo.GetValue(myItem, null);

значение будет содержать "7"