Qual é o aspecto mais difícil ou mais incompreendido do LINQ? [fechadas]

282

Antecedentes: No próximo mês, darei três palestras sobre ou pelo menos incluir LINQno contexto de C#. Gostaria de saber em quais tópicos vale a pena prestar bastante atenção, com base no que as pessoas podem achar difícil de entender ou no que elas podem ter uma impressão errada. Eu não vou ser especificamente falando sobre LINQa SQLou o Entity Framework, exceto como exemplos de como as consultas podem ser executadas remotamente usando árvores de expressão (e geralmente IQueryable).

Então, o que você achou difícil LINQ? O que você viu em termos de mal-entendidos? Os exemplos podem ser os seguintes, mas não se limite!

  • Como o C#compilador trata expressões de consulta
  • Expressões lambda
  • Árvores de expressão
  • Métodos de extensão
  • Tipos anônimos
  • IQueryable
  • Adiado versus execução imediata
  • Streaming vs execução em buffer (por exemplo, OrderBy é adiado, mas em buffer)
  • Variáveis ​​locais implicitamente digitadas
  • Lendo assinaturas genéricas complexas (por exemplo, Enumerable.Join )
Jon Skeet
fonte
3
Gostaria de saber quando você fará essas palestras e se há alguma maneira de vê-las on-line.
Mark Heath
2
Primeira palestra: Copenhague, 30 de outubro. Espero que isso seja gravado. (Dia inteiro!) Segunda palestra: Londres, 19 de novembro à noite, London .NET Users Group, provavelmente no Push LINQ. Terceira palestra: Reading, 22 de novembro, Developer Developer Day, implementando LINQ to Objects em 60 minutos.
Jon Skeet
1
Downvoters: adicione um comentário explicativo.
911 Jon Skeet
2
@ Jon, desculpe, mas eu preciso fechar isso.
Tim Post
3
@ Tim: É justo - não estava obtendo mais respostas de qualquer maneira. Pessoalmente, acho que acabou sendo construtivo, lembre-se - certamente achei útil ver o que as pessoas acham complicado. Eu provavelmente não teria perguntado isso agora embora ...
Jon Skeet

Respostas:

271

Execução atrasada

JaredPar
fonte
12
Righto - este é claramente o favorito entre os leitores, que é a coisa mais importante para esta pergunta. Também adicionarei "buffer versus streaming" à mistura, pois isso está intimamente relacionado - e muitas vezes não é discutido com tantos detalhes quanto eu gostaria de ver nos livros.
Jon Skeet
10
Realmente? Eu tinha sua natureza preguiçosa apontada para mim tantas vezes enquanto aprendia o Linq, isso nunca foi um problema para mim.
Adam Lassek
26
Concorde com ALassek. A documentação do MSDN indica claramente a natureza de avaliação lenta do LINQ. Talvez o problema real seja a natureza preguiçosa da programação dos desenvolvedores ... =)
Seiti
4
... especialmente quando você percebe que isso se aplica ao LINQ a objetos e não apenas ao LINQ 2 SQL - quando você vê 10 chamadas de método da Web para recuperar uma lista de itens quando já está enumerando a mesma lista de itens e pensou que o lista já foi avaliada
Simon_Weaver 15/02/09
5
Saber qual é a declaração de rendimento e como ela funciona é essencial para o IMHO, para uma compreensão completa do LINQ.
peSHIr
125

Sei que o conceito de execução adiada deve estar sendo adotado até agora, mas este exemplo realmente me ajudou a entender o conceito:

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);
    }
}

O código acima retorna o seguinte:

Before add:
Bob
Alice
Trent

After add:
Bob
Alice
Trent
Mallory
DSO
fonte
2
blogs.msdn.com/b/charlie/archive/2007/12/09/… <- Eu acho que este é o melhor blog para explicar isso na minha opinião. (longe de 2007, não pode acreditar que foi em torno de tanto tempo já)
Phill
104

Que há mais do que apenas LINQpara SQLe os recursos são mais do que apenas um SQLanalisador incorporado na língua.

smaclell
fonte
6
Estou farto de todo mundo pensar que: /
TraumaPony 19/10/08
40
Nem todo mundo faz! Ainda não sei o que é o LINQ to SQL e uso o LINQ o tempo todo.
Robert Rossney 19/10/08
2
Fico tão irritado quando tento explicar algo usando o LINQ e a outra pessoa apenas olha para mim e diz "ohhh, eu não uso o LINQ para nada disso, apenas SQL" :(
Nathan W
13
De acordo, muitas pessoas parecem não entender que o LINQ é uma ferramenta de uso geral.
Matthew Olenik 7/03/09
86

Notação O grande . O LINQ torna incrivelmente fácil escrever algoritmos O (n ^ 4) sem perceber, se você não sabe o que está fazendo.

erikkallen
fonte
16
Que tal um exemplo?
9139 hughdbrown
4
Até o exemplo, talvez ele queira dizer que é muito fácil fazer com que uma cláusula Select contenha muitos operadores Sum (), cada um deles causando outra passagem por todo o conjunto de registros.
Rob Packwood
1
De fato, pode até valer a pena analisar o que é grande notação O e por que é importante, além de alguns exemplos de consultas resultantes ineficientes. Eu acho que é isso que o pôster original estava sugerindo, mas pensei em mencioná-lo de qualquer maneira. - EDIT: só percebi que este post foi de 1,5 anos :-)
zcrar70
7
Isso não seria O (n ^ x), seria O (xn), que é apenas O (n).
Malfist
3
Tentar fazer uma junção sem o operador de junção resultará em O (n ^ x): de i1 no intervalo1 de i2 no intervalo2 de i3 no intervalo3 de i4 no intervalo4 em que i1 == i2 && i3 == i4 selecione novo {i1, i2, i3, i4}. E eu já vi isso escrito antes. Funciona, mas muito lentamente.
MarkPflug
55

Eu acho que o fato de uma Lambdaexpressão poder resolver tanto para uma árvore de expressão quanto para um delegado anônimo, para que você possa passar a mesma lambdaexpressão declarativa para os IEnumerable<T>métodos de IQueryable<T>extensão e de extensão.

Tim Jarvis
fonte
2
Acordado. Eu sou veterano e acabei de perceber que esse elenco implícito estava ocorrendo quando comecei a escrever meu próprio QueryProvider
TheSoftwareJedi
53

Me levou maneira muito tempo para perceber que muitos métodos de extensão LINQ, tais como Single(), SingleOrDefault()etc têm sobrecargas que levam lambdas.

Você pode fazer :

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

e não preciso dizer isso - que algum tutorial ruim me deu o hábito de fazer

Where(x => x.id == id).Single()
Simon_Weaver
fonte
+1, muito bom. Vou manter isso em mente.
Pretzel
4
Eu continuo esquecendo isso também. Também é verdade Count(), entre outros. Você sabe se há alguma diferença de desempenho, além do bônus óbvio de legibilidade do código?
Justin Morgan
1
Na universidade, meu professor queria tirar pontos por usar essas sobrecargas !! Eu provei que ele estava errado!
TDaver 16/02
12
Pode parecer estranho, mas eu prefiro a segunda sintaxe. Acho mais legível.
Konamiman
40

No LINQ to SQL, vejo constantemente pessoas que não entendem o DataContext, como ele pode ser usado e como deve ser usado. Muitas pessoas não veem o DataContext como um objeto de Unidade de Trabalho, não um objeto persistente.

Eu já vi muitas vezes em que as pessoas estão tentando escolher um DataContext / sessão / etc, em vez de criar um novo horário para cada operação.

E há o descarte do DataContext antes que o IQueryable seja avaliado, mas isso é mais propício para as pessoas que não entendem o IQueryable do que o DataContext.

O outro conceito com o qual vejo muita confusão é a sintaxe de consulta versus a sintaxe de expressão. Usarei o que for mais fácil nesse ponto, geralmente mantendo a Expressão Sintaxe. Muitas pessoas ainda não percebem que produzirão a mesma coisa no final, afinal, o Query é compilado no Expression.

Aaron Powell
fonte
2
Aviso: A unidade de trabalho pode ser um pequeno programa com o contexto de dados como um singleton.
graffic 29/11/08
15
Você não deve usar o DataContext em um singleton, ele não é seguro para threads.
Aaron Powell
3
@Slace, nem todos os programas são multitheaded, por isso é OK para ter o DataContext como um singleton em um monte de software "desktop"
Ian Ringrose
2
Fui mordido por isso (usando o DataContext como um singleton) quando fiz meu primeiro projeto LINQ to SQL. Não acho que a documentação e os livros tornem isso óbvio o suficiente. Na verdade, acho que o nome poderia ser melhorado, mas não sei como.
Roger Lipscombe
1
Foi preciso ler os artigos de ScottGu no Linq várias vezes para colocar isso na minha cabeça.
precisa
34

Eu acho que a parte incompreendida do LINQ é que é uma extensão de linguagem , não uma extensão ou construção de banco de dados.

LINQé muito mais que isso LINQ to SQL.

Agora que a maioria de nós já usou LINQcoleções, NUNCA voltaremos!

LINQ é o recurso mais significativo para o .NET desde Generics no 2.0 e Anonymous Types no 3.0.

E agora que temos o Lambda, mal posso esperar pela programação paralela!

Chris
fonte
Eu diria que é mais significativo que os tipos anônimos e possivelmente ainda mais que os genéricos.
Justin Morgan.
26

Eu, com certeza, gostaria de saber se preciso saber o que são árvores de expressão e por quê.

Robert Rossney
fonte
6
Acho que vale a pena saber o que são árvores de expressão e por que elas existem, mas não os detalhes de como construí-las. (Eles são uma dor para construir a mão, mas o compilador irá fazer um grande trabalho ao converter uma expressão lambda.)
Jon Skeet
3
Na verdade, eu estava pensando em fazer algumas entradas de blog em árvores de expressão (desde que eu as "obtenho"). Acho que manipular árvores de expressão é muito útil ...
Marc Gravell
No entanto, não acho que sejam úteis para as conversas de Jon ;-p
Marc Gravell
3
Só me preocupo que as árvores de expressão sejam como a declaração de rendimento: algo que se mostrou incrivelmente valioso, apesar do fato de eu não entender o que era inicialmente.
Robert Rossney 19/10/08
1
Marc Gravell Gostaria de ler as entradas do seu blog sobre o assunto. Ansioso por isso
Alexandre Brisebois
20

Eu sou bastante novo no LINQ. Aqui estão as coisas que eu tropecei na minha primeira tentativa

  • Combinando várias consultas em um
  • Depurando efetivamente as consultas LINQ no Visual Studio.
Mark Heath
fonte
21
A depuração do LINQ é um tópico por si só e importante. Eu acho que a maior fraqueza do LINQ é que ele permite escrever blocos de lógica arbitrariamente complexa que você não pode avançar.
Robert Rossney 19/10/08
3
estes podem ser um bom lugar para pad uso LINQ
Maslow
2
Concordo com entusiasmo; foi por isso que escrevi LINQ Secrets Revealed: Chaining and Debugging , recém publicado no Simple-Talk.com, que você pode encontrar assistência.
Michael Sorens
Sim, o LinqPad é uma ótima ferramenta secundária para o desenvolvimento de suas consultas LINQ. Especialmente quando você inicia e é novo nas convenções / padrões.
Buffalo
20

Algo que eu não percebi originalmente era que a sintaxe do LINQ não requer IEnumerable<T>ou IQueryable<T>funciona, o LINQ é apenas sobre correspondência de padrões.

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

Aqui está a resposta (não, eu não escrevi esse blog, Bart De Smet, e ele é um dos melhores blogueiros do LINQ que eu encontrei).

Aaron Powell
fonte
1
Você também pode achar interessante neste post de blog: msmvps.com/blogs/jon_skeet/archive/2008/02/29/…
Jon Skeet
Bom post Jon (eu assino o seu blog, apenas recentemente).
Aaron Powell
19

Eu ainda tenho problemas com o comando "let" (que eu nunca encontrei um uso) e SelectMany (que eu usei, mas não tenho certeza se fiz direito)

James Curran
fonte
2
Sempre que você quiser introduzir uma variável, você usaria uma instrução let. Pense em um loop tradicional em que você está introduzindo variáveis ​​nele e dando um nome a cada variável para ajudar na legibilidade do código. Às vezes, também é bom que você tenha uma instrução let avaliando um resultado de função, que você pode selecionar e ordenar sem precisar avaliar o resultado duas vezes.
Rob Packwood
'let' permite que você faça tipos compostos. Coisas úteis.
315:
19

Entendendo quando a abstração entre os provedores do Linq vaza. Algumas coisas funcionam em objetos, mas não em SQL (por exemplo, .TakeWhile). Alguns métodos podem ser traduzidos para SQL (ToUpper), enquanto outros não. Algumas técnicas são mais eficientes em objetos, enquanto outras são mais eficazes em SQL (diferentes métodos de junção).

Denis Phillips
fonte
1
Esse é um ponto muito bom. Não ajuda que o Intellisense mostre TODOS eles e, geralmente, compila. Então você explode em tempo de execução. Espero que o VS 2010 faça um trabalho melhor ao mostrar métodos de extensão relevantes.
23242 Jason Short
12

Algumas coisas.

  1. Pessoas pensando em Linq como Linq to SQL.
  2. Algumas pessoas pensam que podem começar a substituir todos os foreach / logic por consultas Linq sem considerar essas implicações de desempenho.
Krishna Kumar
fonte
11

OK, devido à demanda, escrevi algumas das coisas da Expressão. Não estou 100% satisfeito com a forma como o blogueiro e o LiveWriter conspiraram para formatá-lo, mas o resultado será por enquanto ...

Enfim, aqui vai ... Eu adoraria qualquer feedback, especialmente se houver áreas em que as pessoas querem mais informações.

Aqui está , goste ou odeie ...

Marc Gravell
fonte
10

Algumas das mensagens de erro, especialmente de LINQ para SQL, podem ser bastante confusas. sorrir

Fui mordido pela execução adiada algumas vezes, como todo mundo. Acho que a coisa mais confusa para mim foi o Provedor de Consultas do SQL Server e o que você pode ou não fazer com ele.

Ainda estou impressionado com o fato de que você não pode fazer um Sum () em uma coluna decimal / dinheiro que às vezes está vazia. Usar DefaultIfEmpty () simplesmente não funcionará. :(

Per Erik Stendahl
fonte
1
Shold ser Prette fácil de bater um caso em que a consulta ao trabalho make soma
Esben Skov Pedersen
9

Penso que uma grande coisa a ser abordada no LINQ é como você pode ter problemas em termos de desempenho. Por exemplo, usar a contagem de LINQ como uma condição de loop não é muito, muito inteligente.

Steve
fonte
7

Que o IQueryable aceite os dois Expression<Func<T1, T2, T3, ...>>e Func<T1, T2, T3, ...>, sem dar uma dica sobre a degradação do desempenho no segundo caso.

Aqui está um exemplo de código, que demonstra o que quero dizer:

[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
fonte
Você pode explicar? Não estou seguindo ...
Pretzel
@Pretzel Adicionei um exemplo de código que demonstra meu problema.
Valera Kolupaev 30/09/10
Obrigado pelo exemplo de código! Muito útil.
Buffalo
6

Não sei se qualifica como incompreendido - mas para mim, simplesmente desconhecido.

Fiquei satisfeito em saber sobre o DataLoadOptions e como posso controlar quais tabelas são unidas quando faço uma consulta específica.

Veja aqui para mais informações: MSDN: DataLoadOptions

Martin
fonte
6

Eu diria que o aspecto mais mal compreendido (ou não deve ser entendido?) Do LINQ é o IQueryable e os provedores LINQ personalizados .

Estou usando o LINQ há algum tempo e estou completamente confortável no mundo IEnumerable, e posso resolver a maioria dos problemas com o LINQ.

Mas, quando comecei a ler e ler sobre o IQueryable, o Expressions e os fornecedores de linq personalizados, isso fez minha cabeça girar. Veja como o LINQ to SQL funciona, se você quiser ver uma lógica bastante complexa.

Estou ansioso para entender esse aspecto do LINQ ...

Jack Ukleja
fonte
6

Como a maioria das pessoas disse, acho que a parte mais incompreendida é assumir que o LINQ é apenas um substituto para o T-SQL. Meu gerente, que se considera um guru do TSQL, não nos deixou usar o LINQ em nosso projeto e até odeia o MS por lançar algo assim !!!

HashName
fonte
Muitas pessoas o usam como um substituto para o TSQL. A maioria deles nunca ouviu falar de um plano de execução.
27610 erikkallen
+1 porque concordo com seu gerente, pelo menos na medida em que permite LINQ to SQL em qualquer projeto. O LINQ to Objects é outra questão completamente.
NotMe
5

O que var representa quando uma consulta é executada?

É iQueryable, iSingleResult, iMultipleResult, ou fá-lo mudar de acordo com a implementação. Há alguma especulação sobre o uso (o que parece ser) de digitação dinâmica versus digitação estática padrão em C #.

user31939
fonte
O AFAIK var sempre é a classe concreta em questão (mesmo que seja do tipo anônima), portanto nunca é IQueryable, ISingleResult ou qualquer coisa que comece com 'I' (as classes concretas que começam com 'I' não precisam se aplicar).
Motti
5

Como é fácil aninhar um loop é algo que eu não acho que todos entendam.

Por exemplo:

from outerloopitem in outerloopitems
from innerloopitem in outerloopitem.childitems
select outerloopitem, innerloopitem
Rob Packwood
fonte
+1, uau. isso é muito poderoso.
Pretzel
4

group by ainda faz minha cabeça girar.

Qualquer confusão sobre execução adiada deve poder ser resolvida percorrendo algum código simples baseado em LINQ e brincando na janela de inspeção.

Richard Ev
fonte
1
Descobri que implementar um pouco de LINQ to Objects por diversão realmente ajuda :) Mas sim, é um pouco confuso - certamente, se eu não faço nenhum LINQ há algum tempo, preciso voltar às assinaturas. Da mesma forma "ingressar" vs "ingressar em" geralmente me deixa ...
Jon Skeet
4

Consultas compiladas

O fato de você não poder encadear IQueryableporque são chamadas de método (embora ainda nada mais seja traduzível para SQL!) E que é quase impossível contornar isso é incompreensível e cria uma enorme violação do DRY. Eu preciso do meu IQueryablepara ad-hoc, no qual não tenho consultas compiladas (só tenho consultas compiladas para cenários pesados), mas nas consultas compiladas não posso usá-las e, em vez disso, preciso escrever a sintaxe regular novamente. Agora estou fazendo as mesmas subconsultas em 2 lugares, preciso lembrar de atualizar ambos se algo mudar, e assim por diante. Um pesadelo.

Alex
fonte
4

Eu acho que o equívoco número 1 sobre o LINQ to SQL é que você AINDA TEM DE CONHECER o SQL para fazer uso efetivo dele.

Outra coisa incompreendida sobre o Linq to Sql é que você ainda precisa reduzir a segurança do banco de dados ao ponto de absurdo para fazê-lo funcionar.

Um terceiro ponto é que o uso de Linq para Sql junto com classes dinâmicas (significando que a definição de classe é criada em tempo de execução) causa uma quantidade enorme de compilação just-in-time. O que pode absolutamente matar o desempenho.

Eu não
fonte
4
É muito benéfico já conhecer SQL, no entanto. Alguns SQL emitidos pelo Linq para SQL (e outros ORMs) podem ser totalmente duvidosos, e saber que o SQL ajuda a diagnosticar esses problemas. Além disso, o Linq to SQL pode fazer uso de procedimentos armazenados.
Robert Harvey
2

Como mencionado, carregamento lento e execução adiada

Como o LINQ to Objects e o LINQ to XML (IEnumerable) são diferentes do LINQ to SQL (IQueryable)

COMO criar uma camada de acesso a dados, camada de negócios e camada de apresentação com LINQ em todas as camadas .... e um bom exemplo.

Máquina de cinzas
fonte
Os dois primeiros que eu posso fazer. Eu não gostaria de tentar fazer o terceiro ainda em um "este é o caminho certo para fazê-lo" sentido ...
Jon Skeet
+1, até você apontar, eu não tinha percebido que o LINQ-to-Objects e o LINQ-XML eram IEnumerable em oposição ao LINQ-to-SQL como IQueryable, mas faz sentido. Obrigado!
Pretzel
2

Como a maioria das pessoas disse, acho que a parte mais incompreendida é assumir que o LINQ é apenas um substituto para o T-SQL. Meu gerente, que se considera um guru do TSQL, não nos deixou usar o LINQ em nosso projeto e até odeia o MS por lançar uma coisa dessas !!!

stackuser1
fonte
2

Transações (sem usar o TransactionScope)

Naeem Sarfraz
fonte