Учитывая тип ExpressionType.MemberAccess, как я могу получить значение поля? - PullRequest
32 голосов
/ 27 октября 2008

Я анализирую дерево выражений. Как получить значение этого поля с учетом NodeType ExpressionType.MemberAccess

Из документов C # MSDN: MemberAccess - это узел, представляющий чтение из поля или свойства.

Фрагмент кода был бы невероятно, невероятно полезным. Заранее спасибо !!!

Мой код выглядит примерно так:

public static List<T> Filter(Expression<Func<T, bool>> filterExp) 
{
//the expression is indeed a binary expression in this case
BinaryExpression expBody = filterExp.Body as BinaryExpression;

if (expBody.Left.NodeType == ExpressionType.MemberAccess) 
  //do something with ((MemberExpressionexpBody.Left).Name

//right hand side is indeed member access. in fact, the value comes from //aspdroplist.selectedvalue            
if (expBody.Right.NodeType == ExpressionType.MemberAccess)
{
   //how do i get the value of aspdroplist.selected value?? note: it's non-static                        
}

//return a list
}

Ответы [ 2 ]

39 голосов
/ 27 октября 2008

[обновлено для ясности]

Во-первых; приведите Expression к MemberExpression.

A MemberExpression имеет две вещи, представляющие интерес:

  • .Member - PropertyInfo / FieldInfo члену
  • .Expression - выражение для оценки, чтобы получить "obj" для .Member

т.е. если вы можете оценить .Expression как "obj", а .Member - это FieldInfo, то вы можете получить фактическое значение через .GetValue(obj) на FieldInfoPropertyInfo очень похоже).

Проблема в том, что вычисление .Expression очень сложно; -p

Очевидно, вам повезет, если окажется, что это ConstantExpression - но в большинстве случаев это не так; это может быть ParameterExpression (в этом случае вам нужно знать фактическое значение параметра, которое вы хотите оценить), или любую другую комбинацию Expression s.

Во многих случаях простой (возможно, ленивый) вариант - использовать .Compile(), чтобы заставить .NET Framework выполнять тяжелую работу; Затем вы можете оценить лямбду как типизированный делегат (передавая любые параметры, которые требует лямбда). Однако это не всегда вариант.

Чтобы показать, насколько это сложно; рассмотрим этот тривиальный пример (где я жестко запрограммирован на каждом этапе, а не тестирую и т. д.):

using System;
using System.Linq.Expressions;
using System.Reflection;
class Foo
{
    public string Bar { get; set; }
}

static class Program
{
    static void Main()
    {
        Foo foo = new Foo {Bar = "abc"};
        Expression<Func<string>> func = () => foo.Bar;

        MemberExpression outerMember = (MemberExpression)func.Body;
        PropertyInfo outerProp = (PropertyInfo) outerMember.Member;
        MemberExpression innerMember = (MemberExpression)outerMember.Expression;
        FieldInfo innerField = (FieldInfo)innerMember.Member;
        ConstantExpression ce = (ConstantExpression) innerMember.Expression;
        object innerObj = ce.Value;
        object outerObj = innerField.GetValue(innerObj);
        string value = (string) outerProp.GetValue(outerObj, null);    
    }

}
22 голосов
/ 27 октября 2008

Огромное спасибо Марку Гравеллу выше. Я действительно ценил его помощь.

Оказывается, в моем случае. проблема может быть решена через:

object value = Expression.Lambda(expBody.Right).Compile().DynamicInvoke();

Еще раз спасибо, Марк!

...