Khi catch exception và ném lại, dùng throw; (không có biến) để bảo toàn stack trace gốc. Dùng throw ex; sẽ reset stack trace -> mất thông tin debug.
Sai: throw ex (Mất stack trace)
try
{
Method1();
}
catch (Exception ex)
{
throw ex; // SAI: Stack trace bắt đầu từ dòng này
}
Đúng: throw; (Giữ stack trace)
try
{
Method1();
}
catch (Exception ex)
{
// Log, wrap, hoặc chỉ rethrow
throw; // ĐÚNG: Giữ nguyên stack trace từ Method1
}
Ví dụ minh họa
class Program
{
static void Main()
{
try
{
Level2();
}
catch (Exception ex)
{
Console.WriteLine("=== Caught in Main ===");
Console.WriteLine(ex.StackTrace);
}
Console.ReadLine();
}
static void Level2()
{
try
{
Level1();
}
catch
{
throw; // Rethrow đúng cách
}
}
static void Level1()
{
throw new InvalidOperationException("Error at Level1");
}
}
Output Stack Trace (giữ nguyên)
=== Caught in Main ===
at Program.Level1() in ...\Program.cs:line 30
at Program.Level2() in ...\Program.cs:line 24
at Program.Main() in ...\Program.cs:line 14
Wrap Exception (Exception Chaining) - Best Practice
try
{
// Low-level operation
File.ReadAllText("missing.txt");
}
catch (FileNotFoundException ex)
{
// Wrap vào exception cấp cao hơn, PRESERVE InnerException
throw new DataAccessException("Failed to read config file", ex);
// ex trở thành InnerException, stack trace gốc vẫn giữ nguyên
}
// Custom exception
public class DataAccessException : Exception
{
public DataAccessException(string message, Exception inner) : base(message, inner) { }
}
Khi nào dùng throw ex?
Hầu như không bao giờ. Chỉ khi bạn muốn ẩn chi tiết implementation (security) và tạo exception mới hoàn toàn, nhưng vẫn nên set InnerException.
Exception Filters (C# 6+) - Không catch để rethrow
// Chỉ catch khi điều kiện true, không cần rethrow
try
{
Risky();
}
catch (SqlException ex) when (ex.Number == 1205) // Deadlock
{
// Handle deadlock specifically
Retry();
}
catch (SqlException ex) when (ex.Number == 2627) // Unique constraint
{
// Handle duplicate key
LogDuplicate();
}
// Other SqlException -> bubble up automatically (no rethrow needed)
Tóm tắt
throw;-> Giữ stack trace (✓).throw ex;-> Reset stack trace (✗).throw new MyException("msg", ex);-> Wrap, giữInnerException(✓).whenfilter -> Tránh catch/rethrow không cần thiết (✓).