Last() vs LastOrDefault() ใน LINQ
ทั้งสองเมธอดใช้ดึง Element ตัวสุดท้าย ของ Sequence ที่ตรงเงื่อนไข แตแตกต่างที่พฤติกรรมเมื่อ ไม่พบข้อมูล
ความแตกต่างหลัก
| เมธอด | พบข้อมูล | ไม่พบข้อมูล (Empty Sequence) | โยน Exception? |
|---|---|---|---|
| Last() | คืน Element ตัวสุดท้าย | โยน InvalidOperationException | ✅ ใช่ |
| LastOrDefault() | คืน Element ตัวสุดท้าย | คืน default(T) (null/0/false) | ❌ ไม่ |
ตัวอย่างที่ 1: พบข้อมูล (เหมือนกัน)
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
var students = new List
{
new Student { Id = 1, Name = "John" },
new Student { Id = 2, Name = "Jack" },
new Student { Id = 1, Name = "Jill" } // Id=1 ซ้ำ
};
// หา Id = 1 ตัวสุดท้าย
var lastOrDefault = students.LastOrDefault(s => s.Id == 1);
var last = students.Last(s => s.Id == 1);
Console.WriteLine($"LastOrDefault: Id={lastOrDefault.Id}, Name={lastOrDefault.Name}");
Console.WriteLine($"Last: Id={last.Id}, Name={last.Name}");
}
}
class Student
{
public int Id { get; set; }
public string Name { get; set; }
}
ผลลัพธ์:
LastOrDefault: Id=1, Name=Jill Last: Id=1, Name=Jill
ตัวอย่างที่ 2: ไม่พบข้อมูล (ต่างกัน)
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
var students = new List
{
new Student { Id = 1, Name = "John" },
new Student { Id = 2, Name = "Jack" }
};
// หา Id = 3 (ไม่มี)
Console.WriteLine("=== LastOrDefault ===");
var lastOrDefault = students.LastOrDefault(s => s.Id == 3);
Console.WriteLine($"Result: {lastOrDefault?.Name ?? "null"}"); // null
Console.WriteLine($"Is Null: {lastOrDefault == null}"); // True
Console.WriteLine("\n=== Last ===");
try
{
var last = students.Last(s => s.Id == 3);
Console.WriteLine($"Result: {last.Name}");
}
catch (InvalidOperationException ex)
{
Console.WriteLine($"Exception: {ex.Message}"); // Sequence contains no matching element
}
}
}
class Student
{
public int Id { get; set; }
public string Name { get; set; }
}
ผลลัพธ์:
=== LastOrDefault === Result: null Is Null: True === Last === Exception: Sequence contains no matching element
เมื่อไหร่ควรใช้ตัวไหน?
✅ ใช้ Last() เมื่อ:
- มั่นใจว่า ต้องมีข้อมูลอย่างน้อย 1 รายการ ตรงเงื่อนไข
- ข้อมูลว่างเป็น Bug/Exceptional Case ที่ควร Fail Fast
- Domain Logic กำหนดว่าต้องมีข้อมูลเสมอ (เช่น Primary Key Lookup)
✅ ใช้ LastOrDefault() เมื่อ:
- ไม่แน่ใจ ว่ามีข้อมูลหรือไม่
- ข้อมูลว่างเป็น Normal Case (Optional Data)
- ต้องการ Handle เอง (Null Check, Default Value, Alternative Logic)
Default Values สำหรับ Type ต่างๆ
| Type | default(T) |
|---|---|
| Reference Type (class, string, array, delegate) | null |
| Value Type (int, bool, DateTime, struct) | 0, false, DateTime.MinValue, zero-initialized |
| Nullable<T> (T?) | null |
Pattern Matching (C# 7+) สำหรับ LastOrDefault
// Pattern Matching Null Check
var student = students.LastOrDefault(s => s.Id == 3);
if (student is { } foundStudent)
{
Console.WriteLine($"Found: {foundStudent.Name}");
}
else
{
Console.WriteLine("Not found");
}
// Switch Expression (C# 8+)
var message = student switch
{
{ Id: > 0 } => $"Found: {student.Name}",
_ => "Not found"
};
คู่หู: First() vs FirstOrDefault()
เหมือนกันเป๊ะๆ แต่สำหรับ Element ตัวแรก:
| เมธอด | ไม่พบข้อมูล |
|---|---|
First() | โยน InvalidOperationException |
FirstOrDefault() | คืน default(T) |
Single() | โยน Exception (ถ้า 0 หรือ >1) |
SingleOrDefault() | คืน default(T) (ถ้า 0) / โยน Exception (ถ้า >1) |
Best Practices
- Default to LastOrDefault/FirstOrDefault - ปลอดภัยกว่า
- ใช้
Last()เฉพาะเมื่อ Domain Logic รับประกันว่ามีข้อมูล - หลัง
LastOrDefault()ต้อง Null Check เสมอ ก่อนเข้าถึง Property - พิจารณา
Single/SingleOrDefaultหากคาดหวัง Unique Result (Primary Key)
สรุป
- Last() - Strict, โยน Exception ถ้าว่าง → Fail Fast
- LastOrDefault() - Lenient, คืน null/0 → Defensive
- เลือกตาม Business Rule: "ข้อมูลว่างเป็น Error หรือ Normal?"
- คู่หู: First/FirstOrDefault, Single/SingleOrDefault