Dado un tipo ExpressionType.MemberAccess, ¿cómo obtengo el valor de campo?

c# expression-trees reflection

Pregunta

Estoy analizando un Árbol de Expresión. Dado un NodeType de ExpressionType.MemberAccess, ¿cómo obtengo el valor de ese campo?

Desde documentos C # MSDN: MemberAccess es un nodo que representa la lectura de un campo o propiedad.

Un fragmento de código sería increíblemente, increíblemente útil. ¡¡¡Gracias por adelantado!!!

Mi código se ve algo como esto:

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
}

Respuesta aceptada

[actualizado para mayor claridad]

Primero; lanzar la Expression a una Expression MemberExpression .

Un MemberExpression tiene dos cosas de interés:

  • .Member - PropertyInfo / FieldInfo al miembro
  • .Expression - la expresión para evaluar para obtener el "obj" para el .Member

es decir, si puede evaluar la .Expression a "obj", y .Member es un FieldInfo , entonces puede obtener el valor real a través de .GetValue(obj) en FieldInfo (y PropertyInfo es muy similar).

El problema es que evaluar la .Expression es muy difícil ;-p

Obviamente, tienes suerte si resulta ser una ConstantExpression , pero en la mayoría de los casos no lo es; podría ser una ParameterExpression (en cuyo caso deberá conocer el valor real del parámetro que desea evaluar), o cualquier otra combinación de Expression s.

En muchos casos, una opción simple (quizás perezosa) es usar .Compile() para obtener el marco .NET para hacer el trabajo pesado; luego puede evaluar la lambda como un delegado mecanografiado (pasando cualquier parámetro que requiera la lambda). Sin embargo, esto no siempre es una opción.

Para mostrar lo complejo que es esto; Considere este ejemplo trivial (donde he codificado en cada paso, en lugar de probar, etc.):

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

}

Respuesta popular

Muchas gracias a Marc Gravell arriba. Realmente aprecié su ayuda.

Resulta, en mi caso. El problema se puede resolver a través de:

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

Gracias de nuevo Mark!



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow