Introduction: The Familiar Fear of Every C# Developer
\nImagine this: you are writing a query to a database or an in-memory collection. You need to get the first element that satisfies a condition. You are sure that such an element definitely exists. Or are you not sure? This is where the dance begins: .First() or .FirstOrDefault()?
This question is a real hit on Stack Overflow with thousands of views. And for good reason. The choice between these two methods can mean the difference between clean, predictable code and a sudden InvalidOperationException in Production. Let's finally figure out once and for all which method to use when, and forget about doubts forever.
The Main Point in Short: What's the Difference?
\nBoth methods do almost the same thing: they return the first element of a sequence that satisfies a condition (or just the first element if no condition is specified). But there is a critical difference:
\n- \n
- .First() — if the element is not found, it throws a
System.InvalidOperationException. \n - .FirstOrDefault() — if the element is not found, it returns the default value for the type (
nullfor reference types,0forint,falseforbool, etc.). \n
It seems simple. But the devil, as always, is in the details.
\n\nWhen to Use .First(): When "It Must Exist, Period"
\nUse .First() when your business logic strictly guarantees that the element exists. If it doesn't — that's an exceptional situation, an error in the data or application logic.
Example 1: Searching by a Unique Identifier
\nIf you are looking for a user by their Primary Key in the database (e.g., by Id), and you are sure that such a user exists, use .First():
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 // We expect a user with this ID to exist.\n // If not — this is a serious problem, better let the exception be thrown.\n return _context.Users.First(u => u.Id == userId);\n }\n}\nAn exception in this case is an alarm signal. It says: "Hey, the data is corrupted, or someone passed an invalid ID." You will catch this exception higher up the stack and handle it as a critical error.
\n\nExample 2: First Element After Sorting (Guaranteed)
\nIf you sort a list and take the first element, and the list definitely has elements:
\nvar highestScore = players\n .OrderByDescending(p => p.Score)\n .First(); // There cannot be 0 players; we checked this earlier\nIf you have previously verified that the collection is not empty (e.g., if (players.Any())), then .First() is your choice.
When to Use .FirstOrDefault(): When the Element Might Not Exist
\nThe golden rule: If the absence of a result is a normal situation, not an error, use .FirstOrDefault().
Example 1: Optional Search
\nImagine we are looking for an order by its number, but the order might not have been created yet:
\npublic Order FindOrderByNumber(string orderNumber)\n{\n // The order might not exist. That's normal.\n return _context.Orders\n .FirstOrDefault(o => o.OrderNumber == orderNumber);\n // Returns null if the order is not found.\n}\nAfter calling this method, we must check the result for null:
var order = FindOrderByNumber("ORD-12345");\nif (order != null)\n{\n // Work with the order\n Console.WriteLine($"Order found: {order.Id}");\n}\nelse\n{\n Console.WriteLine("Order not found. Creating a new one.");