2011-01-18 13 views
6

Tenga en cuenta la siguiente expresión:Heurística para "esto" y cierres ¿está bien? (árboles de expresión)

class A { 
    int x; 
    public void Method(int y) { 
     Expression<Func<bool>> expr=() => x == y; 
     //... 

Aquí, la expresión implica un cierre creado automáticamente para y, y una referencia a this de tipo A para la (implícita) this.x. Ambos se representarán como MemberExpression en un ConstantExpression en el árbol de expresiones. Dada una expresión como expr o una expresión más complicada con esta referencia y/o cierre, quiero identificar que un particular ConstantExpression es en realidad "este" o un cierre implícitamente construido para poder regenerar C# desde un árbol de expresiones (ExpressionToCode).

Creé una "solución" usando algunas heurísticas ya que no parece haber una solución perfecta.

  • cierres y this en lambda de siempre están en ConstantExpressions.
  • Cierres y this nunca son null.
  • Ambos son clases, no tipos de valores: no se puede capturar una referencia a this desde una estructura. Eso es bastante afortunado, porque decir default(StructType).Method() desde this.Method() sería imposible siempre que this == default(StructType).
  • tipos internos (String, enumeraciones, decimales, Tipo, todas las primitivas) son constantes en realidad de verdad, no this o un cierre
  • Los cierres y los tipos anónimos empezar con < y están anotados con CompilerGeneratedAttribute
    • nombres de cierre contienen el cadena DisplayClass, tipos anónimos contienen AnonymousType
    • Los tipos anónimos son genéricos, los cierres no lo son.
    • Los cierres son clases anidadas, los tipos anónimos no lo son.
  • this debe ser un tipo normal: no CompilerGenerated y no se inicia con <

¿Son las heurísticas anteriores suficientes para distinguir entre reales constantes, this, los cierres y los tipos anónimos? Es decir. ¿Hay casos en que estos heurísticos fallan o me falta alguno? ¿Es probable que se rompa en futuras versiones de .NET?

Editar: primero hice esta pregunta en una forma abierta, sin resultado; Reescribí la pregunta para incluir lo que he encontrado hasta ahora. Cualquier sugerencia muy apreciadas - mañana en expiración de la recompensa, alguna idea es bienvenida ...

+0

¿Estás seguro de que tu suposición es correcta? En mi opinión (no soy un experto;)), la x en la expresión podría ser simplemente una 'referencia' a un int sin ningún conocimiento de la A (y no hay forma de encontrar una A de la expresión) – Guillaume86

+0

ok estoy equivocado, es posible con árboles de expresiones (y es obvio ^^) – Guillaume86

+0

Estoy seguro de que es posible acercarse a una respuesta. No estoy seguro de que sea posible: agregué mis ideas actuales sobre el asunto, que es que necesitarás detectar y diferenciar entre los tipos generados por el compilador, las constantes reales y los tipos de usuario, y observar que el compilador también genera anónimos tipos que no son para cierres. –

Respuesta

2

Ok, me las arreglo para encontrar sobre el Tipo A partir de la expresión:

class Program 
{ 
    class A 
    { 
     int x; 
     public Expression<Func<bool>> Method(int y) 
     { 
      Expression<Func<bool>> expr =() => x == y; 
      return expr; 
     } 
    } 

    static void Main(string[] args) 
    { 
     var expr = new A().Method(10); 

     dynamic body = expr.Body; 

     A instance = body.Left.Expression.Value; 

     Console.Write(instance.ToString()); 

     Console.ReadKey(); 
    } 
} 

La dinámica es sólo para ir rápido.

editar 2: lo tengo

+0

Lo que estás haciendo aquí funciona en * este ejemplo preciso * - pero no funcionará en general. Enumeré la parte relevante de la pregunta con respecto al hecho de que es una expresión * arbitraria *, y agregué un poco de aclaración en cuanto a los por qué y cómo es que esto podría lograrse. ¡Gracias por mirar! –

+0

me temo que lo que quieres hacer es imposible, desde el punto de vista de la expresión, no hay diferencia entre un cierre "implícito" y uno "explícito" ... – Guillaume86

+0

¿Qué quieres decir con cierre explícito? Los cierres son siempre implícitos; y AFAIK generan clases con 'DisplayClass' en el nombre, al menos eso es parte de la heurística que estoy usando hasta ahora. –