2012-02-02 12 views

Respuesta

39

Para su futura referencia, todas las preguntas de este formulario son respondidas por la sección 7.16 de la especificación C#.

Su pregunta específica es contestada por este párrafo:


una expresión de consulta con un segundo from cláusula seguido de un select cláusula

from x1 in e1 
from x2 in e2 
select v 

se traduce en

(e1) . SelectMany(x1 => e2 , (x1 , x2) => v) 

Así su consulta:

var query = from a in sequenceA    
      from b in sequenceB 
      select ...; 

es la misma que

var query = (sequenceA) . SelectMany(a => sequenceB , (a , b) => ...) 

(Tenga en cuenta que, por supuesto, esto supone que el "..." es una expresión, y no, por ejemplo, una expresión seguida por una continuación de la consulta.) respuesta

de HDV señala que

var query = (sequenceA) . SelectMany( 
    a => (sequenceB) . Select(b => ...)); 

también sería lógicamente traducción válida, aunque no es la traducción que realmente realizamos. En los primeros días de la implementación de LINQ, esta era la traducción que elegimos. Sin embargo, a medida que agregas más cláusulas from, hace que las lambdas aniden más y más profundamente, lo que luego presenta al compilador un problema enorme en la inferencia de tipo. Esta elección de traducción arruina el rendimiento del compilador, por lo que presentamos el identificador transparente mecanismo para darnos una forma mucho más barata de representar la seamntics de ámbitos profundamente anidados.

Si estos temas le interesan:

Para más pensamientos sobre por qué lambdas anidadas presentan un problema difícil para el compilador de resolver, ver:

http://blogs.msdn.com/b/ericlippert/archive/2007/03/26/lambda-expressions-vs-anonymous-methods-part-four.aspx

http://blogs.msdn.com/b/ericlippert/archive/2007/03/28/lambda-expressions-vs-anonymous-methods-part-five.aspx

Para obtener más información sobre identificadores transparentes, vea esta publicación de Wes Dyer, quien los implementó en C# 3.0:

http://blogs.msdn.com/b/wesdyer/archive/2006/12/22/transparent-identifiers.aspx

Y mi serie de artículos acerca de ellos:

http://ericlippert.com/2014/07/31/transparent-identifiers-part-one/

+3

Tenga en cuenta que la "Especificación del lenguaje C#" es un documento Word descargable y, por lo tanto, no está indexado por la mayoría de los motores de búsqueda y no se puede leer en línea. ¡Tal vez Microsoft podría cambiar eso en el futuro! –

9
var query = sequenceA.SelectMany(a => sequenceB.Select(b => ...)); 

Editar: como se ha señalado por Eric Lippert en los comentarios, esto da los mismos resultados, pero es intencionalmente no cómo se traduce internamente. Vea su respuesta para otra forma de llamar al SelectMany, que corresponde al original. Además, se agregó el b => omitido para mayor claridad.

+0

¿Una variante no anidada como 'var query = sequenceA.SelectMany (a => sequenceB) .Select (...); 'también funciona? –

+0

@ OlivierJacot-Descombes Eso también es posible, pero eso significa que no puede hacer referencia a 'a' dentro del segundo parámetro' Select'. – hvd

+0

@hdv: Ninguno de ustedes tiene razón. Tiene razón al señalar que en el comentario de Olivier, ha perdido la variable de rango 'a'. Pero en ambas traducciones, ambos han perdido la variable de rango 'b'. ¿A dónde entró 'b' en tu traducción? ¿Qué pasa si '...' se refiere a 'b'? ¡Necesitas otra lambda en algún lado! –

1

Otra manera de escribir sería:

var query = a.Join(b, i => new { }, j => new { }, (i, j) => new { i = i, j = j }); 
+0

Declaraciones 'from' anidadas y' SelectMany' aplanan las enumeraciones anidadas. Es decir. convierten una enumeración de enumeraciones en una enumeración plana que contiene todos los elementos de las enumeraciones anidadas de la fuente. No se unen a dos enumeraciones no relacionadas. –

+0

Lo que hice fue una combinación cruzada, al igual que otras opciones que ha enumerado. La enumeración de resultados también es plana. Sigue adelante e inténtalo :) . –

+0

Ejemplo: Entrada 'cadena [] [] anidado = nueva cadena [] [] { \t nueva cadena [] {" a "," b "," c "}, \t nueva cadena [] {" AA ", "BB", "CC", "DD"}, \t nueva cadena [] {"1", "2", "3"}, }; '. Salida esperada: '" a "," b "," c "," AA "," BB "," CC "," DD "," 1 "," 2 "," 3 "' –

Cuestiones relacionadas