Pregunta

Después de leer " Odd consulta expresiones " por Jon Skeet, probé el código de abajo. Yo esperaba que la consulta LINQ al final de traducir a int query = proxy.Where(x => x).Select(x => x); cuales no se compila porque Where devuelve un int. El código compilado y representa un "Donde (x => x)" a la pantalla y la consulta se establece en 2. Seleccione Nunca se llama, pero tiene que estar allí para el código para compilar. Lo que está pasando?

using System;
using System.Linq.Expressions;

public class LinqProxy
{
    public Func<Expression<Func<string,string>>,int> Select { get; set; }
    public Func<Expression<Func<string,string>>,int> Where { get; set; }
}

class Test
{
    static void Main()
    {
        LinqProxy proxy = new LinqProxy();

        proxy.Select = exp => 
        { 
            Console.WriteLine("Select({0})", exp);
            return 1;
        };
        proxy.Where = exp => 
        { 
            Console.WriteLine("Where({0})", exp);
            return 2;
        };

        int query = from x in proxy
                    where x
                    select x;
    }
}
¿Fue útil?

Solución

Es debido a que su "seleccione x" es efectivamente un no-op - el compilador no se molesta en poner la llamada Select(x => x) al final. Es lo haría si ha quitado la cláusula where sin embargo. Su consulta actual se conoce como un expresión de consulta degenerada . Véase la sección 7.16.2.3 de la especificación C # 4 para más detalles. En particular:

  

A expresión de consulta degenerada es uno que trivialmente selecciona los elementos de la fuente. Una fase posterior de la traducción elimina consultas degenerados introducidas por otros pasos de traducción reemplazándolos con su fuente. Sin embargo es importante para asegurar que el resultado de una expresión de consulta no es el objeto de la fuente en sí, ya que eso revelar el tipo y la identidad de la fuente al cliente de la consulta. Por lo tanto este paso protege consultas degenerados escritas directamente en el código fuente mediante una llamada explícita Selección de la fuente. Es entonces hasta los ejecutores de Selección y otros operadores de consulta para asegurar que estos métodos no devuelven el mismo objeto de origen.

Por lo tanto, tres traducciones (independientemente de la fuente de datos)

// Query                          // Translation
from x in proxy                   proxy.Where(x => x)
where x
select x


from x in proxy                   proxy.Select(x => x)
select x               


from x in proxy                   proxy.Where(x => x)
where x                                .Select(x => x * 2)
select x * 2

Otros consejos

Se compila porque la sintaxis de consulta LINQ es un léxica sustitución . El compilador vueltas

int query = from x in proxy
            where x
            select x;

en

int query = proxy.Where(x => x);     // note it optimises the select away

y sólo después no se puede comprobar si el Where métodos y Select realmente existen en el tipo de proxy. De acuerdo con ello, en el ejemplo específico que diste, Select en realidad no necesita existir para este compilar.

Si tuviera algo como esto:

    int query = from x in proxy
                select x.ToString();

entonces se ve modificado en:

int query = proxy.Select(x => x.ToString());

y el método Select sería llamado.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top