Introduction
Learn about the ExceptionDispatchInfo object, which stores the stack trace information and Watson information that an exception contains at the point where it's captured. The exception can then be thrown later, possibly on another thread, by calling ExceptionDispatchInfo.Throw method.
Examples
💡 In these examples, the task is simple: read a file that does not exist here.
Conventional example
The following example does not use an ExceptionDispatchInfo object; instead, it checks whether the file exists before attempting to read it.
Results are returned by deconstructing a tuple.
private static void ReadFile()
{
var fileName = "nonexistentfile.txt";
if (File.Exists(fileName))
{
var (success, lines, exception) = FileOperations.ReadFile();
}
else
{
SpectreConsoleHelpers.ErrorPill(Justify.Left, $"File '{fileName}' does not exist.");
Log.Information("File '{FileName}' does not exist. Called from {Method} method.",
fileName,
nameof(ReadFile));
}
}
public class FileOperations
{
public static (bool success, string[] lines, Exception exception) ReadFile()
{
try
{
var lines = File.ReadAllLines("NonExistingFile.txt");
return (true, lines, null);
}
catch (Exception e)
{
Log.Error(e, "An error occurred while reading the file.");
return (false, Array.Empty<string>(), e);
}
}
- Uses a try/catch as the user may not have permissions for read access
- Logs the exception to a daily log file
- Returns a tuple
- Success/failure
- Contents of the file on successful read operation
- If an exception is raised, the root exception
ExceptionDispatchInfo example
Here, if a runtime exception is raised ExceptionDispatchInfo.Capture method stores the exception and is return as part of the returning tuple.
public class FileOperations
{
public static (string[] lines, ExceptionDispatchInfo exceptionDispatchInfo) ReadAllLines()
{
string[] lines = null;
ExceptionDispatchInfo exceptionDispatchInfo = null;
try
{
lines = File.ReadAllLines("NonExistingFile.txt");
}
catch (Exception localException)
{
exceptionDispatchInfo = ExceptionDispatchInfo.Capture(localException);
}
return (lines, exceptionDispatchInfo);
}
}
Calling code:
private static void HandleFileReadOperation1()
{
var (lines, exceptionDispatchInfo) = FileOperations.ReadAllLines(); // file does not exist
if (exceptionDispatchInfo is not null)
{
SpectreConsoleHelpers.ErrorPill(Justify.Left, "An error occurred while reading the file:");
ExceptionHelpers.ColorStandard(exceptionDispatchInfo.SourceException);
Log.Error(exceptionDispatchInfo.SourceException, "An error occurred while reading the file.");
if (AnsiConsole.Confirm("Continue with throw?"))
{
exceptionDispatchInfo!.Throw();
}
}
else
{
foreach (var line in lines)
{
Console.WriteLine(line);
}
}
}
- Return results in a tuple
- Lines read if the read operation was successful
- Display lines
- ExceptionDispatchInfo instance on a failed read operation
- Display and log error
- Ask to throw the captured exception
- Lines read if the read operation was successful
Source code
- Written in Microsoft Visual Studio 2026
- .NET Core 10
Summary
💡 ExceptionDispatchInfo is to be considered to be simply another tool in a developer's toolbox.
Choosing the right path to follow should never be determined by a class or language feature, but by business requirements.
ExceptionDispatchInfo has been available for a long time, but most developers don't know about it, which is why they're more likely to use it because it's new to them. As stated above, do not force the use of ExceptionDispatchInfo.
Applies
| Product | Versions |
|---|---|
| .NET | Core 1.0, Core 1.1, Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7, 8, 9, 10, 11 |
| .NET Framework | 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1 |
| .NET Standard | 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 2.0, 2.1 |
| UWP | 10.0 |
See also
Exception Handling (C# Programming Guide)
Libraries
- All operations use SeriLog NuGet package to log runtime issues.
- Spectre.Console library is used to enhance console output
Top comments (0)