2008-10-26 13 views
30

Estoy analizando un árbol de expresiones. Dado un NodeType de ExpressionType.MemberAccess, ¿cómo obtengo el valor de ese campo?Dado un tipo ExpressionType.MemberAccess, ¿cómo obtengo el valor del campo?

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

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

Mi código es como la siguiente:

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

38

[actualizado para mayor claridad]

Primera; lanzar el Expression a un MemberExpression.

Un MemberExpression tiene dos cosas de interés:

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

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

El problema es que la evaluación de la .Expression es muy difícil ;-P

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

En muchos casos, una opción simple (quizás floja) es usar .Compile() para hacer que el .NET framework haga el trabajo pesado; luego puede evaluar el lambda como un delegado tipeado (pasando los parámetros que requiere el lambda). Sin embargo, esto no siempre es una opción.

Para mostrar lo complejo que es esto; considerar este ejemplo trivial (donde he programado en forma fija a 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);  
    } 

} 
+0

Muchas gracias Marc. El valor de la propiedad .Expression es ... algo más interesante: \t {value (ASP.usercontrols_mycontro_ascx) .controlname} –

+0

estoy haciendo mucho con genéricos y reflexión, por lo que recuperar el valor a través de propertyinfo/fieldinfo no funciona porque No estoy seguro de dónde sacar el objeto de referencia ... ¿puedo extraerlo de memberexpression o methodinfo? –

+1

Funcionará ... pero el problema es que necesita evaluar el.Expresión como un valor para alimentar como el "obj" para FieldInfo/PropertyInfo. ¿No puedes simplemente usar .Compile() y ejecutar el lambda como un delegado? Mucho más fácil que analizar ... –

21

agradecimiento por lo tanto a Marc Gravell anteriormente. Realmente aprecié su ayuda.

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

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

Gracias de nuevo Mark!

+0

¡justo lo que necesitaba! –

+5

o mejor 'object value = Expression.Lambda > (Expression.Convert (expBody.Right, typeof (object))). Compile(). Invoke()' –

+0

Lo triste: es muy lento. – ren

Cuestiones relacionadas