Я разбираю дерево выражений. Учитывая 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
}





[обновлено для ясности]
Первый; преобразовать Expression в MemberExpression.
У MemberExpression есть два интересных момента:
PropertyInfo / FieldInfo членут.е. если вы можете оценить .Expression как "obj", а .Member - это FieldInfo, то вы можете получить фактическое значение через .GetValue(obj) на FieldInfo (и PropertyInfo очень похож).
Проблема в том, что оценить .Expression очень сложно ;-p
Очевидно, вам повезет, если окажется, что это ConstantExpression, но в большинстве случаев это не так; это может быть ParameterExpression (в этом случае вам нужно знать фактическое значение параметра, которое вы хотите оценить) или любая другая комбинация Expression.
Во многих случаях простой (возможно, ленивый) вариант - использовать .Compile(), чтобы заставить платформу .NET выполнять тяжелую работу; затем вы можете оценить лямбда как типизированный делегат (передав любые параметры, которые требуются лямбда). Однако это не всегда вариант.
Чтобы показать, насколько это сложно; рассмотрим этот тривиальный пример (где я жестко программировал на каждом этапе, а не тестировал и т. д.):
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);
}
}
Я много делаю с дженериками и отражением, поэтому получение значения через propertyinfo / fieldinfo не работает, потому что я не уверен, откуда вытащить ссылающийся объект ... могу ли я вытащить это из выражения members или methodinfo?
Это будет работать ... но проблема в том, что вам нужно оценить .Expression как значение для подачи в качестве "obj" для FieldInfo / PropertyInfo. Разве вы не можете просто использовать .Compile () и выполнять лямбда-выражение в качестве делегата? Намного проще, чем разбирать ...
Обратите внимание: если лямбда параметризована, но у вас нет конкретного параметра - тогда вы будете бороться ... но такие вещи, как ConstantExpression, должны работать нормально.
Большое спасибо, Марк !!! действительно ... выше и выше здесь. в конечном итоге проблема в том, что левая часть является двоичным выражением ... а правая часть не является постоянным выражением. я собираюсь обновить свой вопрос с помощью некоторого кода
Большое спасибо Марку Гравеллу выше. Я очень признателен за его помощь.
Оказывается, в моем случае. проблему можно решить с помощью:
object value = Expression.Lambda(expBody.Right).Compile().DynamicInvoke();
Еще раз спасибо, Марк!
или лучше object value = Expression.Lambda<Func<object>>(Expression.Convert(expBody.Right, typeof(object))).Compile().Invoke()
Печальная часть: это очень медленно.
Большое спасибо, Марк. Значение свойства .Expression ... кое-что более интересное: {value (ASP.usercontrols_mycontro_ascx) .controlname}