Quando usar .First e quando usar .FirstOrDefault com LINQ?

824

Pesquisei e não encontrei uma resposta clara sobre quando .Firste o que usar .FirstOrDefaultcom o LINQ.

  • Quando você gostaria de usar .First? Somente quando você deseja capturar a exceção se nenhum resultado for retornado?

    var result = List.Where(x => x == "foo").First();
  • E quando você gostaria de usar .FirstOrDefault? Quando você sempre deseja o tipo padrão, se não houver resultado?

    var result = List.Where(x => x == "foo").FirstOrDefault();
  • E, quanto a isso, e o Take?

    var result = List.Where(x => x == "foo").Take(1);
Metro Smurf
fonte
86
.Firste .FirstOrDefaultambos os predicados tomar como argumentos, por isso, var result = List.Where(x => x == "foo").First();poderia ser reescrita comovar result = List.First(x => x == "foo");
Rian Schmits
59
Não se esqueça de considerar Singlee SingleOrDefault. Eu odeio quando as pessoas usam Firstquando realmente querem dizer Single; )
BartoszKP
19
Single ou SingleOrDefault lançaria uma exceção se houver mais de um elemento retornado! Eu acho que FirstOrDefault é melhor nos casos mais comuns!
precisa
21
O ponto é que, quando você espera um resultado único, deve dizer isso e a exceção indica que sua lógica falhou.
NetMage 24/10
1
Considere também que o uso .FirstOrDefault()sempre oferece a oportunidade de lançar uma exceção mais significativa. Se uma exceção de sequência for lançada e mais de uma .First()em um método, pode ser difícil discernir qual instrução é o problema.
StingyJack 6/11

Respostas:

807

Eu usaria First()quando sei ou espero que a sequência tenha pelo menos um elemento. Em outras palavras, quando é uma ocorrência excepcional que a sequência está vazia.

Use FirstOrDefault()quando souber que precisará verificar se havia um elemento ou não. Em outras palavras, quando é legal que a sequência esteja vazia. Você não deve confiar no tratamento de exceções para a verificação. (É uma prática ruim e pode prejudicar o desempenho).

Finalmente, a diferença entre First()e Take(1)é que First()retorna o próprio elemento, enquanto Take(1)retorna uma sequência de elementos que contém exatamente um elemento.

driis
fonte
4
@driis - eu imagino que podemos usar o mantra da exceção excepcional ao escolher entre First e FirstOrDefault. Obrigado pela resposta clara.
Metro Smurf
5
A única coisa que eu acrescentaria é que, se o valor padrão para o tipo que você está selecionando puder ser um valor válido, por exemplo, seu resultado pode ser o valor int 0, então lidar com a exceção parece ser a melhor maneira de lidar com isso. .
PeterBelm
25
Risque isso, eu encontrei uma maneira muito melhor de realizar isso, use: DefaultIfEmpty (-1) .Em primeiro lugar ()
PeterBelm
5
Take não retorna exatamente um elemento, ele retorna no máximo um elemento (se você especificar 1, é claro). Também pode retornar 0 elementos, se a sequência estiver inicialmente vazia.
SPIRiT_1984
3
@RoyiNamir, sim, no contexto da pergunta em que o parâmetro a seguir é 1. Também observei que em parênteses imediatamente após essa frase.
driis
272

.Firstlançará uma exceção quando não houver resultados. .FirstOrDefaultnão, simplesmente retornará nulo (tipos de referência) ou o valor padrão do tipo de valor. (por exemplo, como 0para um int.) A questão aqui não é quando você deseja o tipo padrão, mas mais: você está disposto a lidar com uma exceção ou com um valor padrão? Como as exceções devem ser excepcionais, FirstOrDefaulté preferível quando você não tem certeza se deseja obter resultados de sua consulta. Quando logicamente os dados devem estar lá, o tratamento de exceções pode ser considerado.

Skip()e Take()são normalmente usados ​​ao configurar a paginação nos resultados. (Como mostrar os 10 primeiros resultados e os próximos 10 na página seguinte etc.)

Espero que isto ajude.

Jeroen Landheer
fonte
5
@ Jeroen - bom argumento sobre melhores casos de uso para usar o Skip / Take.
Metro Smurf
4
+1 para explicação que .FirstOrDefaultretornará nulo para tipos de referência. Eu estava confuso sobre o que seria um objeto "padrão". Esta resposta esclareceu isso.
9788 Mike Taverne #
115

.First()emitirá uma exceção se não houver nenhuma linha a ser retornada, enquanto .FirstOrDefault()retornará o valor padrão ( NULLpara todos os tipos de referência).

Portanto, se você estiver preparado e disposto a lidar com uma possível exceção, tudo .First()bem. Se você preferir verificar o valor de retorno de != nullqualquer maneira, então .FirstOrDefault()é sua melhor escolha.

Mas acho que também é uma preferência pessoal. Use o que fizer mais sentido para você e se adapte melhor ao seu estilo de codificação.

marc_s
fonte
66

Primeiro()

  1. Retorna o primeiro elemento de uma sequência.
  2. Ele gera um erro quando Não há elemento no resultado ou a fonte é nula.
  3. você deve usá-lo, se mais de um elemento for esperado e você desejar apenas o primeiro elemento.

FirstOrDefault ()

  1. Retorna o primeiro elemento de uma sequência ou um valor padrão se nenhum elemento for encontrado.
  2. Ele gera um erro Apenas se a fonte for nula.
  3. você deve usá-lo, se mais de um elemento for esperado e você desejar apenas o primeiro elemento. Também é bom se o resultado estiver vazio.

Temos uma tabela UserInfos, que possui alguns registros, como mostrado abaixo. Com base nesta tabela abaixo, criei um exemplo ...

Tabela UserInfo

Como usar o First ()

var result = dc.UserInfos.First(x => x.ID == 1);

Há apenas um registro em que ID == 1. Deve retornar esse
ID de registro : 1 Nome: Manish Sobrenome: Dubey Email: [email protected]

var result = dc.UserInfos.First(x => x.FName == "Rahul");   

Existem vários registros em que FName == "Rahul". O primeiro registro deve ser retornado.
ID: 7 Nome: Rahul Sobrenome: Sharma E-mail: [email protected]

var result = dc.UserInfos.First(x => x.ID ==13);

Não há registro com o ID == 13. Um erro deve ocorrer.
InvalidOperationException: Sequence não contém elementos

Como usar FirstOrDefault ()

var result = dc.UserInfos.FirstOrDefault(x => x.ID == 1);

Há apenas um registro em que ID == 1. Deve retornar esse
ID de registro : 1 Nome: Manish Sobrenome: Dubey Email: [email protected]

var result = dc.UserInfos.FirstOrDefault(x => x.FName == "Rahul");

Existem vários registros em que FName == "Rahul". O primeiro registro deve ser retornado.
ID: 7 Nome: Rahul Sobrenome: Sharma E-mail: [email protected]

var result = dc.UserInfos.FirstOrDefault(x => x.ID ==13);

Não há registro com o ID == 13. O valor de retorno é nulo

Espero que ajude você a entender quando usar First()ou FirstOrDefault().

Mukesh Kumar
fonte
4
Na minha opinião, a declaração "Um erro deve ocorrer". sob o terceiro FirstOrDefault () - o exemplo é enganador.
Jannik
Olá, você explica bem, mas estou um pouco confuso quando os dados são obtidos da junção e quando o ID não existia em uma tabela de chaves estrangeiras naquele momento, qual é usada? No momento, estou usando First (), mas depois de ler sua resposta, não faço a menor idéia. Por favor, ajude
Brijesh Mavani
20

Primeiro de tudo, Takeé um método completamente diferente. Ele retorna um IEnumerable<T>e não um T, então está pronto.

Entre Firste FirstOrDefault, você deve usar Firstquando tiver certeza de que um elemento existe e, se não existir, ocorrerá um erro.

A propósito, se sua sequência contiver default(T)elementos (por exemplo null) e você precisar distinguir entre estar vazio e o primeiro elemento null, não poderá usá-lo FirstOrDefault.

Mehrdad Afshari
fonte
2
@Mehrdad - ótimos pontos, re: .First retorna IEnumerable e quando não usar FirstOrDefault.
Metro Smurf
15

Primeiro:

  • Retorna o primeiro elemento de uma sequência
  • Lança exceção: não há elementos no resultado
  • Use when: Quando mais de 1 elemento for esperado e você desejar apenas o primeiro

FirstOrDefault:

  • Retorna o primeiro elemento de uma sequência ou um valor padrão se nenhum elemento for encontrado
  • Lança exceção: somente se a fonte for nula
  • Use when: Quando mais de 1 elemento for esperado e você desejar apenas o primeiro. Também está ok o resultado ficar vazio

De: http://www.technicaloverload.com/linq-single-vs-singleordefault-vs-first-vs-firstordefault/

user2051770
fonte
10

Outra diferença a ser observada é que, se você estiver depurando um aplicativo em um ambiente de Produção, poderá não ter acesso aos números das linhas, identificando quais .First() pode ser difícil instrução em um método lançou a exceção.

A mensagem de exceção também não incluirá nenhuma expressão Lambda que você possa ter usado, o que tornaria qualquer problema ainda mais difícil de depurar.

É por isso que eu sempre uso, FirstOrDefault()mesmo sabendo que uma entrada nula constituiria uma situação excepcional.

var customer = context.Customers.FirstOrDefault(i => i.Id == customerId);
if (customer == null)
{
   throw new Exception(string.Format("Can't find customer {0}.", customerId));
}
Kye
fonte
5

Primeiro()

Quando você souber que o resultado contém mais de 1 elemento esperado e você deve apenas o primeiro elemento da sequência.

FirstOrDefault ()

FirstOrDefault () é como First (), exceto que, se nenhum elemento corresponder à condição especificada, ele retornará o valor padrão do tipo subjacente da coleção genérica. Não lança InvalidOperationException se nenhum elemento encontrado. Mas a coleção de elemento ou uma sequência é nula do que gera uma exceção.

Nimesh khatri
fonte
Olá, você explica bem, mas estou um pouco confuso quando os dados são obtidos da junção e quando o ID não existia em uma tabela de chaves estrangeiras naquele momento, qual é usada? No momento, estou usando First (), mas depois de ler sua resposta, não faço a menor idéia. Por favor, ajude
Brijesh Mavani
4

Este tipo de função pertence aos operadores de elemento. Alguns operadores de elementos úteis são definidos abaixo.

  1. First / FirstOrDefault
  2. Last / LastOrDefault
  3. Single / SingleOrDefault

Usamos operadores de elemento quando precisamos selecionar um único elemento de uma sequência com base em uma determinada condição. Aqui está um exemplo.

  List<int> items = new List<int>() { 8, 5, 2, 4, 2, 6, 9, 2, 10 };

O operador First () retorna o primeiro elemento de uma sequência após satisfazer a condição. Se nenhum elemento for encontrado, ele lançará uma exceção.

int result = items.Where (item => item == 2) .Primeiro ();

O operador FirstOrDefault () retorna o primeiro elemento de uma sequência após satisfazer a condição. Se nenhum elemento for encontrado, ele retornará o valor padrão desse tipo.

int result1 = items.Where (item => item == 2) .FirstOrDefault ();

Sheo Dayal Singh
fonte
bem explicado com um exemplo fácil de entender.
Arslan Bhatti
3

Encontrei um site que funciona para explicar a necessidade de FirstOrDefault
http://thepursuitofalife.com/the-linq-firstordefault-method-and-null-resultsets/
Se não houver resultados para uma consulta e você desejar ligar para First () ou Única () para obter uma única linha ... Você receberá uma exceção "Sequência não contém elementos".

Isenção de responsabilidade: nunca usei o LINQ, portanto, desculpe-me se isso estiver errado.

NULO
fonte
2
someList.First(); // exception if collection is empty.
someList.FirstOrDefault(); // first item or default(Type)

Qual usar? Deve ser decidido pela lógica de negócios, e não pelo medo de falha na exceção / programa.

Por exemplo, se a lógica de negócios disser que não podemos ter zero transações em nenhum dia útil (suponha). Então você não deve tentar lidar com esse cenário com alguma programação inteligente. Eu sempre usarei First () nessa coleção e deixarei o programa falhar se algo mais estragar a lógica do negócio.

Código:

var transactionsOnWorkingDay = GetTransactionOnLatestWorkingDay();
var justNeedOneToProcess = transactionsOnWorkingDay.First(): //Not FirstOrDefault()

Eu gostaria de ver outros comentários sobre isso.

Manish Basantani
fonte
O valor padrão para os tipos de referência e nulos é nulo.
Dsa
Falhar rapidamente é bom - no entanto, para o cenário que você descreveu, prefiro ver Primeiro, fazer com que falhe, capte a exceção e retorne um erro significativo. Como catch (InvalidOperationException e) {throw new InvalidOperationException ("Não é possível ter zero transações em um dia!", E)}; Mas sim, usar o padrão para evitar lidar com um problema real de lógica de negócios é muito ruim.
Mathieson
1

Ok, deixe-me dar meus dois centavos. First / Firstordefault são para quando você usa o segundo construtor. Não vou explicar o que é, mas é quando você sempre usa um potencial porque não deseja causar uma exceção.

person = tmp.FirstOrDefault(new Func<Person, bool>((p) =>
{
    return string.IsNullOrEmpty(p.Relationship);
}));
Arian
fonte
Não exatamente. O primeiro construtor é amplamente usado quando você precisa recuperar apenas um item ou evitar um erro de compilação ao atribuir o resultado a um valor que não é uma matriz e você tem certeza de que a consulta retorna exatamente um resultado. Enquanto isso pode parecer mais rápido para usar o segundo construtor em vez de usar um .Where adicional () (porque você acha LINQ pára avaliando itens na lista depois de encontrar o primeiro) sempre pára no primeiro elemento
usr-local-ΕΨΗΕΛΩΝ
0

Outros descreveram muito bem a diferença entre First()e FirstOrDefault(). Quero dar mais um passo na interpretação da semântica desses métodos. Na minha opinião, FirstOrDefaultestá sendo muito usado em demasia. Na maioria dos casos, ao filtrar dados, você espera recuperar uma coleção de elementos que correspondam à condição lógica ou um único elemento único por seu identificador exclusivo - como usuário, livro, publicação etc. por que podemos chegar ao ponto de dizer que FirstOrDefault()é um cheiro de código, não porque há algo errado com ele, mas porque está sendo usado com muita frequência. Esta postagem no blog explora o tópico em detalhes. IMO na maioria das vezesSingleOrDefault() é uma alternativa muito melhor, portanto, preste atenção a esse erro e use o método mais apropriado que represente claramente seu contrato e expectativas.

Vasil Kosturski
fonte
-6

No linq, de várias maneiras para implementar uma consulta simples e simples em coleções, basta escrever junções no sql, um filtro pode ser aplicado primeiro ou por último, dependendo da necessidade e necessidade.

Aqui está um exemplo em que podemos encontrar um elemento com um ID em uma coleção. Para adicionar mais detalhes, os métodos First, FirstOrDefaultretornariam o mesmo ideal quando uma coleção tiver pelo menos um registro. Se, no entanto, é aceitável uma coleção estar vazia. Em seguida First, retornará uma exceção, mas FirstOrDefaultretornará nullou o padrão. Por exemplo, intretornará 0. Portanto, o uso de tal é considerado preferência pessoal, mas é melhor usá-lo FirstOrDefaultpara evitar o tratamento de exceções. aqui está um exemplo em que, atropelamos uma coleção de lista de transações

Venkat
fonte