.First vs FirstOrDefault em C#: Quando usar cada um?

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: O medo familiar de todo desenvolvedor C#

\n

Imagine a situação: você está escrevendo uma consulta ao banco de dados ou a uma coleção em memória. Precisa obter o primeiro elemento que satisfaz uma condição. Você tem certeza de que esse elemento existe? Ou não tem tanta certeza? É aí que começa a dança: .First() ou .FirstOrDefault()?

\n

Essa pergunta é um verdadeiro sucesso no Stack Overflow, com milhares de visualizações. E não é à toa. A escolha entre esses dois métodos pode significar a diferença entre um código limpo e previsível e um InvalidOperationException inesperado em Produção. Vamos entender de uma vez por todas quando usar cada método e acabar com as dúvidas para sempre.

\n\n

Resumo: Qual é a diferença?

\n

Ambos os métodos fazem quase a mesma coisa: retornam o primeiro elemento de uma sequência que satisfaz uma condição (ou apenas o primeiro elemento, se nenhuma condição for especificada). Mas há uma diferença crucial:

\n
    \n
  • .First() — se o elemento não for encontrado, lança a exceção System.InvalidOperationException.
  • \n
  • .FirstOrDefault() — se o elemento não for encontrado, retorna o valor padrão para o tipo (null para tipos de referência, 0 para int, false para bool, etc.).
  • \n
\n

Parece simples, não é? Mas o diabo, como sempre, está nos detalhes.

\n\n

Quando usar .First(): Quando "tem que existir, e ponto final"

\n

Use .First() quando sua lógica de negócios garantir estritamente que o elemento existe. Se ele não existir, é uma situação excepcional, um erro nos dados ou na lógica da aplicação.

\n\n

Exemplo 1: Busca por identificador único

\n

Se você está buscando um usuário pela Chave Primária no banco de dados (por exemplo, pelo Id) e tem certeza de que o usuário existe, use .First():

\n
public class UserService\n{\n    private readonly AppDbContext _context;\n\n    public UserService(AppDbContext context)\n    {\n        _context = context;\n    }\n\n    public User GetUserById(int userId)\n    {\n        // Esperamos que o usuário com este ID exista.\n        // Se não existir, é um problema sério; é melhor lançar uma exceção.\n        return _context.Users.First(u => u.Id == userId);\n    }\n}
\n

A exceção neste caso é um sinal de alerta. Ela diz: "Ei, os dados estão corrompidos, ou alguém passou um ID inválido". Você capturará essa exceção em um nível superior e a tratará como um erro crítico.

\n\n

Exemplo 2: Primeiro elemento após ordenação (garantido)

\n

Se você está ordenando uma lista e pegando o primeiro elemento, e a lista com certeza tem elementos:

\n
var highestScore = players\n    .OrderByDescending(p => p.Score)\n    .First(); // Não pode haver 0 jogadores, verificamos isso antes
\n

Se você verificou previamente que a coleção não está vazia (por exemplo, if (players.Any())), então .First() é a sua escolha.

\n\n

Quando usar .FirstOrDefault(): Quando o elemento pode não existir

\n

Regra de ouro: Se a ausência de um resultado é uma situação normal, e não um erro, use .FirstOrDefault().

\n\n

Exemplo 1: Busca opcional

\n

Imagine que estamos procurando um pedido pelo número, mas o pedido pode ainda não ter sido criado:

\n
public Order FindOrderByNumber(string orderNumber)\n{\n    // O pedido pode não existir. Isso é normal.\n    return _context.Orders\n        .FirstOrDefault(o => o.OrderNumber == orderNumber);\n    // Retornará null se o pedido não for encontrado.\n}
\n

Após chamar este método, somos obrigados a verificar se o resultado é null:

\n
var order = FindOrderByNumber("ORD-12345");\nif (order != null)\n{\n    // Trabalhamos com o pedido\n    Console.WriteLine($"Pedido encontrado: {order.Id}");\n}\nelse\n{\n    Console.WriteLine("Pedido não encontrado. Criando um novo.");                

Blogs

Book Recommendations