Khi LINQ query không tìm thấy phần tử nào, hành vi phụ thuộc vào phương thức thực thi (execution method).
Các trường hợp phổ biến
| Phương thức | Kết quả khi rỗng | Ném Exception? |
|---|---|---|
ToList() / ToArray() | Empty List/Array (Count == 0) | Không |
First() | - | Có - InvalidOperationException "Sequence contains no elements" |
FirstOrDefault() | default(T) (null cho reference, 0 cho int...) | Không |
Single() | - | Có - "Sequence contains no elements" |
SingleOrDefault() | default(T) | Không |
Last() | - | Có |
LastOrDefault() | default(T) | Không |
ElementAt(index) | - | Có - ArgumentOutOfRangeException |
ElementAtOrDefault(index) | default(T) | Không |
Any() | false | Không |
All() | true (vacuous truth) | Không |
Count() | 0 | Không |
Sum() / Average() | 0 / Exception (InvalidOperationException) | Average ném exception |
Ví dụ minh họa
var numbers = new List { 1, 2, 3 };
var empty = numbers.Where(x => x > 10); // Empty sequence
// Safe methods
Console.WriteLine(empty.ToList().Count); // 0
Console.WriteLine(empty.FirstOrDefault()); // 0 (default(int))
Console.WriteLine(empty.SingleOrDefault()); // 0
Console.WriteLine(empty.Any()); // False
Console.WriteLine(empty.All(x => x > 0)); // True (vacuous truth)
Console.WriteLine(empty.Count()); // 0
Console.WriteLine(empty.Sum()); // 0
// Unsafe methods (throw)
// empty.First(); // InvalidOperationException
// empty.Single(); // InvalidOperationException
// empty.Average(); // InvalidOperationException
Best Practice: An toàn với kết quả rỗng
// 1. Dùng OrDefault cho single element
var first = list.FirstOrDefault(x => x > 10);
if (first != 0) { /* ... */ } // Hoặc first != default
// 2. Kiểm tra Any() trước
if (list.Any(x => x > 10))
{
var first = list.First(x => x > 10); // Safe vì đã check Any
}
// 3. DefaultIfEmpty cho query syntax / projection
var result = from x in list.Where(x => x > 10).DefaultIfEmpty()
select x.Name ?? "N/A";
// 4. Nullable reference types (C# 8+) giúp catch tại compile time
#nullable enable
string? firstName = list.Where(x => x > 10).Select(x => x.Name).FirstOrDefault();
// firstName có thể null -> compiler cảnh báo nếu dereference unchecked
LINQ to SQL / Entity Framework
FirstOrDefault(),SingleOrDefault()-> trả vềnull(entity class).ToList()-> trả vềList<T>rỗng.Count()-> trả về 0.Any()-> dịch sang SQLEXISTS, hiệu quả.
Tóm lại: Luôn ưu tiên các phương thức OrDefault, Any, ToList khi không chắc chắn có dữ liệu. Tránh First(), Single(), Average() trên sequence có thể rỗng.