Expressão fluente e de consulta - existe algum benefício de um sobre o outro?

255

O LINQ é uma das maiores melhorias no .NET desde os genéricos e economiza muito tempo e linhas de código. No entanto, a sintaxe fluente parece vir muito mais natural para mim do que a sintaxe da expressão de consulta.

var title = entries.Where(e => e.Approved)
    .OrderBy(e => e.Rating).Select(e => e.Title)
    .FirstOrDefault();

var query = (from e in entries
             where e.Approved
             orderby e.Rating
             select e.Title).FirstOrDefault();

Existe alguma diferença entre os dois ou existe algum benefício particular de um sobre o outro?

JarrettV
fonte
1
Para consultas complexas, acho a sintaxe lambda mais compreensível / legível, mas a sintaxe da consulta é simplesmente mais bonita.
Nawfal 1/08/15

Respostas:

255

Nem é melhor: eles atendem a diferentes necessidades. A sintaxe da consulta é própria quando você deseja aproveitar várias variáveis ​​de intervalo . Isso acontece em três situações:

  • Ao usar a palavra-chave let
  • Quando você possui vários geradores ( de cláusulas)
  • Ao fazer junções

Aqui está um exemplo (dos exemplos do LINQPad):

string[] fullNames = { "Anne Williams", "John Fred Smith", "Sue Green" };

var query =
  from fullName in fullNames
  from name in fullName.Split()
  orderby fullName, name
  select name + " came from " + fullName;

Agora compare isso com a mesma coisa na sintaxe do método:

var query = fullNames
  .SelectMany (fName => fName.Split().Select (name => new { name, fName } ))
  .OrderBy (x => x.fName)
  .ThenBy  (x => x.name)
  .Select  (x => x.name + " came from " + x.fName);

A sintaxe do método, por outro lado, expõe toda a gama de operadores de consulta e é mais concisa com consultas simples. Você pode obter o melhor dos dois mundos misturando sintaxe de consulta e método. Isso geralmente é feito em consultas LINQ to SQL:

var query =
  from c in db.Customers
  let totalSpend = c.Purchases.Sum (p => p.Price)    // Method syntax here
  where totalSpend > 1000
  from p in c.Purchases
  select new { p.Description, totalSpend, c.Address.State };
Joe Albahari
fonte
2
Boa resposta. Você pode me contar um pouco mais sobre o que ".Selecione (nome => novo {nome, fName})" está fazendo?
quillbreaker
12
Ele seleciona a palavra individual (anne, williams, john, etc) junto com o nome completo em um tipo anônimo. Isso permite que você "carregue" o nome completo original para ter acesso ao nome completo e à palavra individual no restante da consulta.
91110 Joe Albahari
58

Prefiro usar o último (às vezes chamado de "sintaxe de compreensão de consulta") quando posso escrever toda a expressão dessa maneira.

var titlesQuery = from e in entries
                  where e.Approved
                  orderby e.Rating
                  select e.Titles;

var title = titlesQuery.FirstOrDefault();

Assim que eu tiver que adicionar (parênteses) e .MethodCalls(), eu mudo.

Quando uso o primeiro, costumo colocar uma cláusula por linha, como esta:

var title = entries
    .Where (e => e.Approved)
    .OrderBy (e => e.Rating)
    .Select (e => e.Title)
    .FirstOrDefault();

Acho isso um pouco mais fácil de ler.

Jay Bazuzi
fonte
29

Cada estilo tem seus prós e contras. A sintaxe da consulta é mais agradável quando se trata de junções e possui a útil palavra-chave let, que facilita a criação de variáveis ​​temporárias dentro de uma consulta.

A sintaxe fluente, por outro lado, tem muito mais métodos e operações que não são expostos pela sintaxe da consulta. Além disso, como são apenas métodos de extensão, você pode escrever o seu próprio.

Descobri que toda vez que começo a escrever uma instrução LINQ usando a sintaxe da consulta, acabo tendo que colocá-la entre parênteses e voltar a usar métodos de extensão LINQ fluentes. A sintaxe da consulta simplesmente não possui recursos suficientes para usar por si só.

James Newton-King
fonte
"Como são apenas métodos de extensão, você pode escrever o seu." - você enfrentaria esse problema? stackoverflow.com/a/3850254/1175496
The Red Pea
20

No VB.NET, prefiro a sintaxe da consulta.

Detesto repetir a feia Functionpalavra-chave:

Dim fullNames = { "Anne Williams", "John Fred Smith", "Sue Green" };
Dim query =
     fullNames.SelectMany(Function(fName) fName.Split().
     Select(Function(Name) New With {Name, fName})).
     OrderBy(Function(x) x.fName).
     ThenBy(Function(x) x.Name).
     Select(Function(x) x.Name & " came from " & x.fName)

Esta consulta pura é muito mais legível e sustentável na minha opinião:

query = From fullName In fullNames
        From name In fullName.Split()
        Order By fullName, name
        Select name & " came from " & fullName

A sintaxe de consulta do VB.NET também é mais poderosa e menos detalhada do que em C #: https://stackoverflow.com/a/6515130/284240

Por exemplo, esta consulta LINQ to DataSet (Objects)

VB.NET:

Dim first10Rows = From r In dataTable1 Take 10

C #:

var first10Rows = (from r in dataTable1.AsEnumerable() 
                   select r)
                   .Take(10);
Tim Schmelter
fonte
9
Minha simpatia pelos desenvolvedores de VB que não podem usar o estilo de consulta.
Nawfal
1
Seu último exemplo de C # é muito simplista para ser valioso: você simplesmente escreveria `dataTable1.AsEnumerable (). Take (10);
Emyr
@ Emyr: meu último parágrafo, que começa com "a sintaxe de consulta do VB.NET também é mais poderosa e menos detalhada do que em C #", está apenas comparando a sintaxe de consulta do VB.NET com o C #, você está usando a sintaxe do método.
Tim Schmelter
15

Não recebo a sintaxe da consulta. Não há razão para isso em minha mente. let pode ser obtido com os tipos .Select e anônimo. Eu só acho que as coisas parecem muito mais organizadas com a "pontuação" lá dentro.

Caçador de Instâncias
fonte
9
Várias associações podem ficar bastante trabalhosas rapidamente com a sintaxe fluente. No entanto, geralmente uso-me fluentemente - a menos que haja junções.
Roman Starkov
1
@ Hunter Instance: O mesmo aqui. Levei um bom tempo para começar a entender a idéia de sintaxe fluente. Em combinação com o poderoso enumerável e a idéia de funções "puras", agora eu realmente aprecio isso, e anteriormente situações complicadas que não tinham uma boa representação de código. Para ye-ole-SQL-parte do cérebro, ainda é uma benção ter sintaxe de consulta.
Xan-Kun Clark-Davis
13

A interface fluente, se houver apenas um onde. Se eu precisar de uma seleção ou pedido, geralmente uso a sintaxe de consulta.

James Curran
fonte
8

A sintaxe fluente parece realmente mais poderosa, mas também deve funcionar melhor para organizar o código em pequenos métodos reutilizáveis.

Kozyarchuk
fonte
5

Eu sei que esta pergunta está marcada com c #, mas a sintaxe fluente é dolorosamente detalhada com o VB.NET.

Larsenal
fonte
4

Gosto muito da sintaxe Fluente e tento usá-la onde posso, mas em alguns casos, por exemplo, onde uso junções, geralmente prefiro a sintaxe Query; nesses casos, acho mais fácil ler e acho que algumas pessoas são mais familiares à sintaxe de consulta (semelhante a SQL) do que lambdas.

CMS
fonte
4

Embora eu compreenda e goste do formato fluente, permaneci no Query por motivos de legibilidade. As pessoas que estão sendo introduzidas no LINQ acharão o Query muito mais confortável de ler.

LizB
fonte
4

Eu prefiro a sintaxe da consulta, pois vim da programação tradicional da Web usando SQL. É muito mais fácil para mim envolver minha cabeça. No entanto, acho que vou começar a utilizar o .Where (lambda), pois é definitivamente muito mais curto.

Steve Tranby
fonte
4

Estou usando o Linq há cerca de 6 meses. Quando comecei a usá-lo, preferi a sintaxe da consulta, pois ela é muito semelhante ao T-SQL.

Mas agora estou gradualmente voltando ao primeiro, pois é fácil escrever trechos reutilizáveis ​​de código como métodos de extensão e apenas encadear eles. Embora eu ache que colocar cada cláusula em sua própria linha ajuda muito na legibilidade.

Antony Scott
fonte
3

Acabei de configurar os padrões da nossa empresa e aplicamos o uso dos métodos de extensão. Eu acho que é uma boa ideia escolher um sobre o outro e não misturá-los no código. Os métodos de extensão são mais parecidos com o outro código.

A sintaxe de compreensão não tem todos os operadores e usa parênteses em torno da consulta e adiciona métodos de extensão, afinal me implora por usar métodos de extensão desde o início.

Mas, na maioria das vezes, é apenas uma preferência pessoal, com algumas exceções.

Rodi
fonte
3
Não aplicarei preferências pessoais. Mas sou eu.
Memet Olsen 23/03