How to rethrow InnerException without losing stack trace in C#?
In .NET 4.5 there is now the ExceptionDispatchInfo
class.
This lets you capture an exception and re-throw it without changing the stack-trace:
using ExceptionDispatchInfo =
System.Runtime.ExceptionServices.ExceptionDispatchInfo;
try
{
task.Wait();
}
catch(AggregateException ex)
{
ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
}
This works on any exception, not just AggregateException
.
It was introduced due to the await
C# language feature, which unwraps the inner exceptions from AggregateException
instances in order to make the asynchronous language features more like the synchronous language features.
C#: Rethrow an exception from a variable while preserving stack trace
That's where ExceptionDispatchInfo comes into play.
It resides inside the System.Runtime.ExceptionServices
namespace.
class Program
{
static void Main(string[] args)
{
ExceptionDispatchInfo edi = null;
try
{
// stuff
throw new Exception("A");
}
catch (Exception ex)
{
edi = ExceptionDispatchInfo.Capture(ex);
}
edi?.Throw();
}
}
The output:
Unhandled exception. System.Exception: A
at EDI_Demo.Program.Main(String[] args) in C:\Users\...\Program.cs:line 16
--- End of stack trace from previous location where exception was thrown ---
at EDI_Demo.Program.Main(String[] args) in C:\Users\...\Program.cs:line 24
- Line 16 is where
throw new Exception("A");
is called - Line 24 is where
edi?.Throw();
is called
How can I rethrow an Inner Exception while maintaining the stack trace generated so far?
It is possible to preserve the stack trace before rethrowing without reflection:
static void PreserveStackTrace (Exception e)
{
var ctx = new StreamingContext (StreamingContextStates.CrossAppDomain) ;
var mgr = new ObjectManager (null, ctx) ;
var si = new SerializationInfo (e.GetType (), new FormatterConverter ()) ;
e.GetObjectData (si, ctx) ;
mgr.RegisterObject (e, 1, si) ; // prepare for SetObjectData
mgr.DoFixups () ; // ObjectManager calls SetObjectData
// voila, e is unmodified save for _remoteStackTraceString
}
This wastes a lot of cycles compared to InternalPreserveStackTrace, but has the advantage of relying only on public functionality. Here are a couple of common usage patterns for stack-trace preserving functions:
// usage (A): cross-thread invoke, messaging, custom task schedulers etc.
catch (Exception e)
{
PreserveStackTrace (e) ;
// store exception to be re-thrown later,
// possibly in a different thread
operationResult.Exception = e ;
}
// usage (B): after calling MethodInfo.Invoke() and the like
catch (TargetInvocationException tiex)
{
PreserveStackTrace (tiex.InnerException) ;
// unwrap TargetInvocationException, so that typed catch clauses
// in library/3rd-party code can work correctly;
// new stack trace is appended to existing one
throw tiex.InnerException ;
}
How to rethrow the inner exception of a TargetInvocationException without losing the stack trace
If you just want to re-throw an inner exception preserving its stack trace, you can do it with a method like this:
public static void Rethrow(this Exception ex)
{
typeof(Exception).GetMethod("PrepForRemoting",
BindingFlags.NonPublic | BindingFlags.Instance)
.Invoke(ex, new object[0]);
throw ex;
}
This technique is used by Rx (and is exposed by them as an extension method Exception.PrepareForRethrow
) and is also used by the Async CTP by its automatic-unwrapping system (without a publicly-exposed API).
Note, however, that this technique is technically unsupported. Hopefully Microsoft will add an official API for this in the future. A suggestion has been opened on Microsoft Connect if you would like to vote for it.
Update: An official API has been added to .NET 4.5: ExceptionDispatchInfo
.
C# How to rethrow an exception from an outer catch
There is no way to rethrow an exception from an outer catch block inside an inner catch block. The best way to achieve this pattern is to note whether or not the inner operation succeeded :
try {
something();
} catch (MyException e1) {
bool recovered=false;
try {
somethingElse();
recovered=true;
} catch {
}
if (!recovered) {
throw;
}
}
What is the proper way to rethrow an exception in C#?
You should always use the following syntax to rethrow an exception. Else you'll stomp the stack trace:
throw;
If you print the trace resulting from throw ex
, you'll see that it ends on that statement and not at the real source of the exception.
Basically, it should be deemed a criminal offense to use throw ex
.
If there is a need to rethrow an exception that comes from somewhere else (AggregateException, TargetInvocationException) or perhaps another thread, you also shouldn't rethrow it directly. Rather there is the ExceptionDispatchInfo that preserves all the necessary information.
try
{
methodInfo.Invoke(...);
}
catch (System.Reflection.TargetInvocationException e)
{
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(e.InnerException).Throw();
throw; // just to inform the compiler that the flow never leaves the block
}
Rethrow an Exception with correct line numbers in the stack trace
You do not lose original exception if you place it in an inner exception.
[WebMethod]
public void ExceptionTest()
{
try
{
throw new Exception("An Error Happened");
}
catch (Exception ex)
{
evlWebServiceLog.WriteEntry(ex.ToString(), EventLogEntryType.Error);
throw new Exception("Your message", ex);
}
}
Related Topics
How to Get Object Size in Memory
Deserialize JSON with Known and Unknown Fields
Reading 64Bit Registry from a 32Bit Application
How to Use a C# Keyword as a Property Name
Generating an Xml Serialization Assembly as Part of My Build
How Does the C# Compiler Detect Com Types
Remove Weird Characters ( a with Hat) from SQL Server Varchar Column
How to Make Sure That String Is Valid JSON Using JSON.Net
How to Get the Name of the Current Method from Code
How to Turn a Datatable to a CSV
How to Use Reflection to Inspect the Code in a Method
How to Deal with Files with a Name Longer Than 259 Characters
Design - Where Should Objects Be Registered When Using Windsor
Async/Await With/Without Awaiting (Fire and Forget)
How to Check the .Net Framework Version
How to Split a String with a String Delimiter
What Is the Correct Way to Use JSON.Net to Parse Stream of JSON Objects