Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

The rethrow statement in C# is a control flow mechanism used exclusively within a catch block to propagate the currently handled exception up the call stack. It is invoked using the throw keyword without an accompanying exception operand and compiles to the rethrow Common Intermediate Language (CIL) instruction.

Syntax

try
{
    // Code that generates an exception
}
catch (Exception ex)
{
    // Intermediate operations
    throw; // The rethrow statement
}

Mechanics and Behavior

When the Common Language Runtime (CLR) encounters a throw; statement, it terminates the execution of the current catch block and resumes the exception propagation process. The CLR searches the call stack for the next enclosing catch block that matches the exception type.

Stack Trace Modification

While the rethrow statement preserves the historical call stack (unlike explicitly throwing the caught exception variable), it does not leave the Exception.StackTrace completely unmodified.
  • throw; (Rethrow): Preserves the previous stack frames, but the CLR updates the current method’s stack frame to reflect the line number of the throw; statement. If the exception was instantiated and originally thrown within the same method, the original line number in the try block is permanently lost and replaced by the line number of the rethrow statement in the catch block.
  • throw ex; (Throwing the caught variable): Compiles to the standard throw CIL instruction. This resets the StackTrace property entirely. The CLR records the line containing throw ex; as the absolute origin of the exception, permanently destroying all historical call stack data from previous frames.

Code Comparison

catch (SqlException ex)
{
    // Preserves previous stack frames, but updates the current frame's 
    // line number to point to this exact line.
    throw; 
}

catch (SqlException ex)
{
    // Resets the stack trace entirely; the exception now originates 
    // from this line, losing all previous call stack history.
    throw ex; 
}

Compiler Constraints

  1. Context Restriction: The parameterless throw; statement is only valid lexically inside a catch block. Attempting to use it outside of a catch block results in compiler error CS0156 (“A throw statement with no arguments is not allowed outside of a catch clause”).
  2. Anonymous and Local Functions: Even when lexically nested entirely inside a catch block, throw; cannot be used within lambdas, anonymous methods, or local functions. Doing so violates the context restriction and results in compiler error CS0156.
  3. Finally Blocks: The statement cannot be used inside a finally block that is a sibling to the catch block. However, it is permitted inside a finally block that is strictly nested within a catch block (e.g., catch { try { } finally { throw; } }).
  4. Standard Nested Blocks: It can be used within standard nested control structures (such as if statements, switch statements, or for loops) provided those structures are directly within the lexical scope of the catch clause and do not cross into a separate function boundary.
Master C# with Deep Grasping Methodology!Learn More