¿Cuál es el aspecto más difícil o más incomprendido de LINQ? [cerrado]

282

Antecedentes: durante el próximo mes, daré tres charlas sobre, o al menos incluidas LINQen el contexto de C#. Me gustaría saber a qué temas vale la pena prestarles una buena atención, en función de lo que las personas puedan encontrar difícil de entender o de lo que puedan tener una impresión errónea. No me referiré específicamente LINQa SQLEntity Framework, excepto como ejemplos de cómo las consultas se pueden ejecutar de forma remota utilizando árboles de expresión (y generalmente IQueryable).

Entonces, ¿qué te ha resultado difícil LINQ? ¿Qué has visto en términos de malentendidos? Los ejemplos pueden ser cualquiera de los siguientes, ¡pero no se limite!

  • Cómo C#trata el compilador las expresiones de consulta
  • Expresiones lambda
  • Árboles de expresión
  • Métodos de extensión
  • Tipos anónimos
  • IQueryable
  • Ejecución diferida vs inmediata
  • Streaming vs ejecución amortiguada (por ejemplo, OrderBy es diferido pero almacenado)
  • Variables locales escritas implícitamente
  • Lectura de firmas genéricas complejas (por ejemplo, Enumerable.Join )
Jon Skeet
fuente
3
Me interesaría saber cuándo va a hacer estas charlas y si hay alguna forma de verlas en línea
Mark Heath,
2
Primera charla: Copenhague, 30 de octubre. Esperemos que esto sea grabado. (¡Todo el día!) Segunda charla: Londres, 19 de noviembre por la noche, London .NET Users Group, probablemente en Push LINQ. Tercera charla: Lectura, 22 de noviembre, Día del desarrollador desarrollador, Implementación de LINQ to Objects en 60 minutos.
Jon Skeet
1
Votantes: agregue un comentario explicativo.
Jon Skeet
2
@ Jon, lo siento, pero necesito cerrar esto.
Tim Post
3
@Tim: Bastante justo, de todos modos no obtenía más respuestas. Personalmente creo que lo hizo llegar a ser constructiva, te importaría - sin duda considerado útil para ver lo que la gente encuentra difícil. Probablemente no lo hubiera preguntado ahora ...
Jon Skeet

Respuestas:

271

Ejecución retrasada

JaredPar
fuente
12
Righto: este es claramente el favorito entre los lectores, que es lo más importante para esta pregunta. También agregaré "buffering vs streaming" en la mezcla, ya que eso está estrechamente relacionado, y a menudo no se discute con tanto detalle como me gustaría ver en los libros.
Jon Skeet
10
De Verdad? Tuve su naturaleza perezosa que me señalaron tantas veces mientras aprendía Linq, nunca fue un problema para mí.
Adam Lassek
26
De acuerdo con ALassek. La documentación de MSDN establece claramente la naturaleza de evaluación diferida de LINQ. Tal vez el verdadero problema es la naturaleza de programación perezosa de los desarrolladores ... =)
Seiti
44
... especialmente cuando se da cuenta de que se aplica a LINQ a los objetos y no solo a LINQ 2 SQL, cuando ve 10 llamadas a métodos web para recuperar una lista de elementos cuando ya está enumerando a través de la misma lista de elementos y piensa que lista ya fue evaluada
Simon_Weaver
55
Saber cuál es la declaración de rendimiento y cómo funciona es, en mi humilde opinión, fundamental para una comprensión profunda de LINQ.
peSHIr
125

Sé que el concepto de ejecución diferida ya debería estar en mi contra, pero este ejemplo realmente me ayudó a comprenderlo de manera práctica:

static void Linq_Deferred_Execution_Demo()
{
    List<String> items = new List<string> { "Bob", "Alice", "Trent" };

    var results = from s in items select s;

    Console.WriteLine("Before add:");
    foreach (var result in results)
    {
        Console.WriteLine(result);
    }

    items.Add("Mallory");

    //
    //  Enumerating the results again will return the new item, even
    //  though we did not re-assign the Linq expression to it!
    //

    Console.WriteLine("\nAfter add:");
    foreach (var result in results)
    {
        Console.WriteLine(result);
    }
}

El código anterior devuelve lo siguiente:

Before add:
Bob
Alice
Trent

After add:
Bob
Alice
Trent
Mallory
DSO
fuente
2
blogs.msdn.com/b/charlie/archive/2007/12/09/… <- Creo que este es el mejor blog para explicarlo en mi opinión. (en 2007, no puedo creer que ya haya existido tanto)
Phill
104

Que hay más que solo LINQpara SQLy las características son más que un SQLanalizador incorporado en el lenguaje.

smaclell
fuente
66
Estoy harto de que todos piensen que: /
TraumaPony
40
¡No todos lo hacen! Todavía no sé qué es LINQ to SQL, y uso LINQ todo el tiempo.
Robert Rossney
2
Me molesta mucho cuando intento explicar algo usando LINQ y la otra persona solo me mira y dice "ohhh, no uso LINQ para algo así, solo SQL" :(
Nathan W
13
De acuerdo, muchas personas no parecen entender que LINQ es una herramienta de propósito general.
Matthew Olenik
86

Gran O notación . LINQ hace que sea increíblemente fácil escribir algoritmos O (n ^ 4) sin darse cuenta, si no sabe lo que está haciendo.

erikkallen
fuente
16
¿Qué tal un ejemplo?
hughdbrown
44
En cuanto a un ejemplo, tal vez se refiera al hecho de que es muy fácil tener una cláusula Select que contenga muchos operadores Sum () con cada uno de ellos causando otro pase sobre todo el conjunto de registros.
Rob Packwood
1
De hecho, incluso podría valer la pena analizar qué es la notación O grande y por qué es importante, así como algunos ejemplos de consultas resultantes ineficientes. Creo que eso era lo que sugería el póster original, pero pensé en mencionarlo de todos modos. - EDITAR: acabo de
darme
77
Eso no sería O (n ^ x), sería O (xn), que es solo O (n).
Malfist
3
Intentar hacer una unión sin el operador de unión dará como resultado O (n ^ x): desde i1 en rango1 desde i2 en rango2 desde i3 en rango3 desde i4 en rango4 donde i1 == i2 && i3 == i4 seleccione nuevo {i1, i2, i3, i4}. Y realmente he visto esto escrito antes. Funciona, pero muy lentamente.
MarkPflug
55

Creo que el hecho de que una Lambdaexpresión puede resolverse tanto en un árbol de expresiones como en un delegado anónimo, por lo que puede pasar la misma lambdaexpresión declarativa tanto a los IEnumerable<T>métodos de IQueryable<T>extensión como a los métodos de extensión.

Tim Jarvis
fuente
2
Convenido. Soy un veterano y me di cuenta de que este casting implícito estaba teniendo lugar cuando comencé a escribir mi propio QueryProvider
TheSoftwareJedi
53

Me tomó forma demasiado tiempo para darse cuenta de que muchos métodos de extensión LINQ tales como Single(), SingleOrDefault()etc tienen sobrecargas que toman lambdas.

Tu puedes hacer :

Single(x => x.id == id)

y no necesito decir esto, que algún mal tutorial me hizo tener la costumbre de hacer

Where(x => x.id == id).Single()
Simon_Weaver
fuente
+1, muy lindo. Lo tendré en cuenta.
Pretzel
44
Sigo olvidando esto también. También es cierto Count(), entre otros. ¿Sabes si hay alguna diferencia de rendimiento, además de la ventaja obvia de la legibilidad del código?
Justin Morgan
1
¡En la universidad, mi profesor quería quitar puntos por usar estas sobrecargas! ¡Le demostré que estaba equivocado!
TDaver
12
Puede sonar extraño, pero prefiero la segunda sintaxis. Lo encuentro más legible.
Konamiman
40

En LINQ to SQL veo constantemente personas que no entienden el DataContext, cómo se puede usar y cómo se debe usar. Demasiadas personas no ven el DataContext por lo que es, un objeto de Unidad de Trabajo, no un objeto persistente.

He visto muchas veces que las personas intentan seleccionar un DataContext / session it / etc en lugar de hacer un nuevo horario para cada operación.

Y luego está deshacerse del DataContext antes de que se haya evaluado el IQueryable, pero eso es más un problema con las personas que no entienden IQueryable que el DataContext.

El otro concepto con el que veo mucha confusión es la sintaxis de consulta frente a la sintaxis de expresión. Usaré la que sea más fácil en ese punto, a menudo con la sintaxis de expresión. Mucha gente todavía no se da cuenta de que al final producirán lo mismo, después de todo, Query se compila en Expression.

Aaron Powell
fuente
2
Advertencia: la unidad de trabajo puede ser un pequeño programa con el contexto de datos como un singleton.
graffic
15
No debe usar el DataContext en un singleton, no es seguro para subprocesos.
Aaron Powell el
3
@Slace, no todos los programas son multitheaded, por lo que está bien tener la DataContext como un producto único en una gran cantidad de software "de escritorio"
Ian Ringrose
2
Esto me mordió (usando DataContext como un singleton) cuando hice mi primer proyecto LINQ to SQL. No creo que la documentación y los libros lo hagan lo suficientemente obvio. En realidad, creo que el nombre podría mejorarse, pero no estoy seguro de cómo.
Roger Lipscombe
1
Me tomó leer las articulaciones de ScottGu en Linq varias veces para que esto me golpeara en la cabeza.
Evan Plaice
34

Creo que la parte incomprendida de LINQ es que es una extensión de lenguaje , no una extensión o construcción de base de datos.

LINQes mucho más que LINQ to SQL.

Ahora que la mayoría de nosotros hemos usado LINQcolecciones, ¡NUNCA volveremos!

LINQ es la característica más importante para .NET desde Generics en 2.0, y Tipos anónimos en 3.0.

Y ahora que tenemos Lambda's, ¡no puedo esperar para la programación paralela!

Chris
fuente
Incluso lo llamaría más significativo que los tipos anónimos, y posiblemente incluso más que los genéricos.
Justin Morgan
26

Por mi parte, me gustaría saber si necesito saber qué son los árboles de expresión y por qué.

Robert Rossney
fuente
66
Creo que vale la pena saber qué son los árboles de expresión y por qué existen, pero no los detalles de cómo construirlos usted mismo. (Son difíciles de construir a mano, pero el compilador hará un gran trabajo al convertir una expresión lambda.)
Jon Skeet
3
En realidad, estaba pensando en hacer algunas entradas de blog en árboles de expresión (ya que las "entiendo"). Me resulta muy útil manipular los árboles de expresión ...
Marc Gravell
Sin embargo, no creo que sean útiles para las charlas de Jon ;-p
Marc Gravell
3
Simplemente me preocupa que los árboles de expresión vayan a ser como la declaración de rendimiento: algo que resultó ser increíblemente valioso a pesar de que no entendí para qué era al principio.
Robert Rossney
1
Marc Gravell Me encantaría leer las entradas de tu blog sobre el tema. Mirando hacia adelante
Alexandre Brisebois
20

Soy bastante nuevo en LINQ. Aquí están las cosas que me tropecé en mi primer intento

  • Combinando varias consultas en una
  • Depuración efectiva de consultas LINQ en Visual Studio.
Mark Heath
fuente
21
La depuración de LINQ es un tema en sí mismo y uno importante. Creo que la mayor debilidad de LINQ es que te permite escribir bloques de lógica compleja arbitraria que no puedes atravesar.
Robert Rossney
3
estos pueden ser un buen lugar para usar LINQ pad
Maslow
2
De acuerdo de todo corazón; por eso escribí LINQ Secrets Revealed: Chaining and Debugging , recién publicado en Simple-Talk.com, para que pueda encontrar ayuda.
Michael Sorens
Sí, LinqPad es una gran herramienta secundaria para desarrollar sus consultas LINQ. Especialmente cuando comienza y es nuevo en las convenciones / patrones.
Buffalo
20

Algo de lo que no me di cuenta originalmente era que la sintaxis de LINQ no requiere IEnumerable<T>o noIQueryable<T> funciona, LINQ se trata solo de la coincidencia de patrones.

texto alternativo http://bartdesmet.info/images_wlw/QIsIQueryabletheRightChoiceforMe_13478/image_thumb_3.png

Aquí está la respuesta (no, no escribí ese blog, lo hizo Bart De Smet, y es uno de los mejores bloggers en LINQ que he encontrado).

Aaron Powell
fuente
1
También puede encontrar interesante esta publicación de blog: msmvps.com/blogs/jon_skeet/archive/2008/02/29/…
Jon Skeet
Bonita publicación Jon (aunque sí me suscribí a tu blog recientemente).
Aaron Powell
19

Todavía tengo problemas con el comando "let" (para el que nunca he encontrado un uso) y SelectMany (que he usado, pero no estoy seguro de haberlo hecho bien)

James Curran
fuente
2
Cada vez que desee introducir una variable, usaría una declaración let. Piense en un ciclo tradicional en el que está introduciendo variables dentro de él y dando un nombre a cada variable para ayudar a la legibilidad del código. A veces también es bueno tener una instrucción let que evalúa el resultado de una función, que luego puede seleccionar y ordenar sin tener que evaluar el resultado dos veces.
Rob Packwood
'let' le permite hacer tipos compuestos. Cosas prácticas
Phill
19

Comprender cuándo se filtra la abstracción entre los proveedores de Linq. Algunas cosas funcionan en objetos pero no en SQL (por ejemplo, .TakeWhile). Algunos métodos pueden traducirse a SQL (ToUpper) mientras que otros no. Algunas técnicas son más eficientes en objetos donde otras son más efectivas en SQL (diferentes métodos de unión).

Denis Phillips
fuente
1
Este es un muy buen punto. No ayuda que Intellisense les muestre TODOS y, por lo general, incluso compilará. Entonces explotas en tiempo de ejecución. Espero que VS 2010 haga un mejor trabajo al mostrar métodos de extensión relevantes.
Jason Short
12

Un par de cosas.

  1. La gente piensa en Linq como Linq para SQL.
  2. Algunas personas piensan que pueden comenzar a reemplazar todo foreach / logic con consultas Linq sin tener en cuenta estas implicaciones de rendimiento.
Krishna Kumar
fuente
11

OK, debido a la demanda, he escrito algunas de las cosas de Expression. No estoy 100% contento con la forma en que blogger y LiveWriter han conspirado para formatearlo, pero lo hará por ahora ...

De todos modos, aquí va ... Me encantaría cualquier comentario, especialmente si hay áreas donde la gente quiere más información.

Aquí está , me gusta o lo odias ...

Marc Gravell
fuente
10

Algunos de los mensajes de error, especialmente de LINQ a SQL, pueden ser bastante confusos. mueca

La ejecución diferida me ha mordido un par de veces como todos los demás. Creo que lo más confuso para mí ha sido el proveedor de consultas de SQL Server y lo que puede y no puede hacer con él.

Todavía estoy sorprendido por el hecho de que no puedes hacer una suma () en una columna decimal / dinero que a veces está vacía. Usar DefaultIfEmpty () simplemente no funcionará. :(

Por Erik Stendahl
fuente
1
Debe ser fácil dar una bofetada a Where en esa consulta para que la suma funcione
Esben Skov Pedersen
9

Creo que una gran cosa para cubrir en LINQ es cómo puedes meterte en problemas en cuanto al rendimiento. Por ejemplo, usar el recuento de LINQ como condición de bucle no es realmente inteligente.

Steve
fuente
7

Que IQueryable acepta ambos Expression<Func<T1, T2, T3, ...>>y Func<T1, T2, T3, ...>, sin dar una pista sobre la degradación del rendimiento en el segundo caso.

Aquí hay un ejemplo de código, que demuestra lo que quiero decir:

[TestMethod]
public void QueryComplexityTest()
{
    var users = _dataContext.Users;

    Func<User, bool>                funcSelector =       q => q.UserName.StartsWith("Test");
    Expression<Func<User, bool>>    expressionSelector = q => q.UserName.StartsWith("Test");

    // Returns IEnumerable, and do filtering of data on client-side
    IQueryable<User> func = users.Where(funcSelector).AsQueryable();
    // Returns IQuerible and do filtering of data on server side
    // SELECT ... FROM [dbo].[User] AS [t0] WHERE [t0].[user_name] LIKE @p0
    IQueryable<User> exp = users.Where(expressionSelector);
}
Valera Kolupaev
fuente
¿Puedes explicar? No estoy siguiendo ...
Pretzel
@Pretzel He agregado un ejemplo de código que demuestra mi problema.
Valera Kolupaev
Gracias por el código de ejemplo! Muy útil.
Buffalo
6

No sé si califica como incomprendido, pero para mí, simplemente desconocido.

Me complació aprender sobre DataLoadOptions y cómo puedo controlar qué tablas se unen cuando hago una consulta en particular.

Consulte aquí para obtener más información: MSDN: DataLoadOptions

Martín
fuente
6

Yo diría que el aspecto más incomprendido (¿o no debería entenderse?) De LINQ es IQueryable y los proveedores de LINQ personalizados .

He estado usando LINQ por un tiempo y estoy completamente cómodo en el mundo IEnumerable, y puedo resolver la mayoría de los problemas con LINQ.

Pero cuando comencé a mirar y leer sobre IQueryable, y Expressions y proveedores de linq personalizados, me dio vueltas la cabeza. Eche un vistazo a cómo funciona LINQ to SQL si desea ver una lógica bastante compleja.

Espero comprender ese aspecto de LINQ ...

Jack Ukleja
fuente
6

Como dijo la mayoría de la gente, creo que la parte más incomprendida es asumir que LINQ es solo un reemplazo para T-SQL. ¡Mi gerente que se considera a sí mismo como un gurú de TSQL no nos permitió usar LINQ en nuestro proyecto e incluso odia a MS por lanzar tal cosa!

rev. HashName
fuente
Demasiadas personas lo usan como reemplazo de TSQL. La mayoría de ellos nunca ha oído hablar de un plan de ejecución.
erikkallen
+1 porque estoy de acuerdo con su gerente, al menos en la medida en que permite LINQ to SQL en cualquier proyecto. LINQ to Objects es un asunto completamente diferente.
NotMe
5

¿Qué representa var cuando se ejecuta una consulta?

¿Es iQueryable, iSingleResult, iMultipleResult, o cambia basa en la aplicación. Hay algunas especulaciones sobre el uso (lo que parece ser) de escritura dinámica frente a la escritura estática estándar en C #.

usuario31939
fuente
AFAIK var siempre es la clase concreta en cuestión (incluso si es un tipo anónimo), por lo que nunca es IQueryable, ISingleResult ni nada que comience con 'I' (las clases concretas que comienzan con 'I' no necesitan aplicarse).
Motti
5

Lo fácil que es anidar un bucle es algo que no creo que todos entiendan.

Por ejemplo:

from outerloopitem in outerloopitems
from innerloopitem in outerloopitem.childitems
select outerloopitem, innerloopitem
Rob Packwood
fuente
+1, whoa Eso es bastante poderoso.
Pretzel
4

group by Todavía me da vueltas la cabeza.

Cualquier confusión sobre la ejecución diferida debe poder resolverse al pasar por un código simple basado en LINQ y jugar en la ventana de observación.

Richard Ev
fuente
1
Descubrí que implementar bastante LINQ to Objects por diversión realmente ayuda :) Pero sí, es un poco confuso, ciertamente si no he hecho LINQ por un tiempo, tengo que volver a las firmas. Del mismo modo "unir" vs "unirse a" a menudo me molesta ...
Jon Skeet
4

Consultas compiladas

El hecho de que no se pueden encadenar IQueryable, ya que son las llamadas de método (mientras todavía otra cosa que traducible SQL!) Y que es casi imposible de trabajo alrededor de ella se mindboggling y crea una enorme violación de SECO. Necesito el mío IQueryablepara ad-hoc en el que no tengo consultas compiladas (solo tengo consultas compiladas para los escenarios pesados), pero en las consultas compiladas no puedo usarlas y en su lugar necesito escribir una sintaxis de consulta regular nuevamente. Ahora estoy haciendo las mismas subconsultas en 2 lugares, necesito recordar actualizar ambas si algo cambia, y así sucesivamente. Una pesadilla.

Alex
fuente
4

Creo que la idea errónea n. ° 1 sobre LINQ to SQL es que TODAVÍA TIENE QUE CONOCER SQL para poder usarlo de manera efectiva.

Otra cosa mal entendida acerca de Linq to Sql es que aún debe reducir la seguridad de su base de datos hasta el punto absurdo para que funcione.

Un tercer punto es que el uso de Linq to Sql junto con las clases dinámicas (lo que significa que la definición de clase se crea en tiempo de ejecución) provoca una enorme cantidad de compilación justo a tiempo. Lo que puede matar absolutamente el rendimiento.

Yo no
fuente
44
Sin embargo, es muy beneficioso saber SQL. Algunos SQL emitidos por Linq a SQL (y otros ORM) pueden ser francamente dudosos, y saber que SQL ayuda a diagnosticar tales problemas. Además, Linq to SQL puede hacer uso de procedimientos almacenados.
Robert Harvey
2

Como se mencionó, carga diferida y ejecución diferida

Cómo LINQ to Objects y LINQ to XML (IEnumerable) son diferentes de LINQ to SQL (IQueryable)

CÓMO construir una capa de acceso a datos, una capa empresarial y una capa de presentación con LINQ en todas las capas ... y un buen ejemplo.

Máquina de ceniza
fuente
Los dos primeros que puedo hacer. No me gustaría intentar hacer la tercera embargo, en una "ésta es la forma correcta de hacerlo" sentido ...
Jon Skeet
+1, hasta que lo señaló, no me había dado cuenta de que LINQ-to-Objects y LINQ-to-XML eran IEnumerable en lugar de LINQ-to-SQL como IQueryable, pero tiene sentido. ¡Gracias!
Pretzel
2

Como dijo la mayoría de la gente, creo que la parte más incomprendida es asumir que LINQ es solo un reemplazo para T-SQL. ¡Mi gerente que se considera a sí mismo como un gurú de TSQL no nos permitió usar LINQ en nuestro proyecto e incluso odia a MS por lanzar tal cosa!

stackuser1
fuente
2

Transacciones (sin usar TransactionScope)

Naeem Sarfraz
fuente