catch exception that is thrown in different thread
You can not catch the exception in Method1. You can, however, catch the exception in Method2 and record it to a variable that the original thread of execution can then read and work with.
In .NET 4 and above, you can use Task<T>
class instead of creating new thread. Then you can get exceptions using .Exceptions
property on your task object.
There are 2 ways to do it:
In a separate method: // You process exception in some task's thread
class Program { static void Main(string[] args) { Task<int> task = new Task<int>(Test); task.ContinueWith(ExceptionHandler, TaskContinuationOptions.OnlyOnFaulted); task.Start(); Console.ReadLine(); } static int Test() { throw new Exception(); } static void ExceptionHandler(Task<int> task) { var exception = task.Exception; Console.WriteLine(exception); } }
In the same method: // You process exception in the caller's thread
class Program { static void Main(string[] args) { Task<int> task = new Task<int>(Test); task.Start(); try { task.Wait(); } catch (AggregateException ex) { Console.WriteLine(ex); } Console.ReadLine(); } static int Test() { throw new Exception(); } }
Note that the exception which you get is AggregateException
. All real exceptions are availible through ex.InnerExceptions
property.
In .NET 3.5 you can use the following code:
// You process exception in the child's thread
class Program { static void Main(string[] args) { Exception exception = null; Thread thread = new Thread(() => SafeExecute(() => Test(0, 0), Handler)); thread.Start(); Console.ReadLine(); } private static void Handler(Exception exception) { Console.WriteLine(exception); } private static void SafeExecute(Action test, Action<Exception> handler) { try { test.Invoke(); } catch (Exception ex) { Handler(ex); } } static void Test(int a, int b) { throw new Exception(); } }
Or // You process exception in the caller's thread
class Program { static void Main(string[] args) { Exception exception = null; Thread thread = new Thread(() => SafeExecute(() => Test(0, 0), out exception)); thread.Start(); thread.Join(); Console.WriteLine(exception); Console.ReadLine(); } private static void SafeExecute(Action test, out Exception exception) { exception = null; try { test.Invoke(); } catch (Exception ex) { exception = ex; } } static void Test(int a, int b) { throw new Exception(); } }
I had a particular problem in that I wanted to use items, containing controls, from an integration test suite, so have to create an STA thread. The code I ended up with is as follows, put here in case others have the same issue.
public Boolean? Dance(String name) {
// Already on an STA thread, so just go for it
if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA) return DanceSTA(name);
// Local variable to hold the caught exception until the caller can rethrow
Exception lException = null;
Boolean? lResult = null;
// A gate to hold the calling thread until the called thread is done
var lGate = new ManualResetEvent(false);
var lThreadStart = new ThreadStart(() => {
try {
lResult = DanceSTA(name);
} catch (Exception ex) {
lException = ex;
}
lGate.Set();
});
var lThread = new Thread(lThreadStart);
lThread.SetApartmentState(ApartmentState.STA);
lThread.Start();
lGate.WaitOne();
if (lException != null) throw lException;
return lResult;
}
public Boolean? DanceSTA(String name) { ... }
This is a direct paste of the code as-is. For other uses I would recommend supplying an action or function as a parameter and invoking that on the thread instead of hard-coding the called method.