3

I have bunch of Asynchronous commands. I want to write try..catch without much of repeating. Example:

_fooCommand = new AsynchronousCommand( () => { action } );
_barCommand = new AsynchronousCommand( () => { action } );

AsynchronousCommand is class that invokes Action using ThreadPool.QueueUserWorkItem( (state) => { action() } );.

Try..catch works well when is inside lambda:

_fooCommand = new AsynchronousCommand( () => { try.exception.catch } );

When outside then not:

try
    _fooCommand = new AsynchronousCommand( () => {...} );
catch

Exception is not catched.

Edit

I want to catch Exception not when creating command: when executing it using command.DoExecute(this) and if possible put try..catch inside lambda.

6
  • 3
    possible duplicate of How to catch exceptions from a ThreadPool.QueueUserWorkItem? Commented Mar 6, 2014 at 15:28
  • No, I know how, I don't know how without repeating and I don't want to change ThreadPool to something else. Commented Mar 6, 2014 at 15:30
  • Move the try/catch into AsynchronousCommand constructor. Commented Mar 6, 2014 at 15:31
  • 3
    You understand that instantiating a new AsynchronousCommand does not actually invoke said command? Thus the try/catch on the outside could not possibly do anything. That being said, it looks like you want the semantics of async/await, which does propagate exceptions in the way you desire -- however they are not an in-place substitute for QueueUserWorkItem since it may or may not leverage threads. Commented Mar 6, 2014 at 15:32
  • @KirkWoll _fooCommand.DoExecute(this) invokes Commented Mar 6, 2014 at 15:33

2 Answers 2

3

Exceptions propagate up the call stack on the thread on which they are thrown. Because the commands run on a thread pool thread, it will be on a different thread to your try ... catch hence it doesn't get caught.

EDIT: Assuming you do actually invoke the command within the try ... catch

Sign up to request clarification or add additional context in comments.

4 Comments

To resolve my problem I must put try..catch inside ThreadPool.QueueWorkItem and eventually invoke Action() from outside lambda if I don't want to write exception handling code in AsynchronousCommand (logging, etc)?
If you are running this code on a threadpool thread, the usual pattern is to have the exception handling within the Action itself, not in the code used to create the AsynchronousCommand or the code used to invoke it.
The Action is a call to external service. I want to catch WebServiceException and WebException but what when I'll need to catch some other exception. Commands can be different.
Just define your own action method, which itself wraps the external call in try ... catch and use that itself as the action when creating the AsynchronousCommand
2

You can get these semantics through the use of await. It when you await something it will schedule the remainder of the method as a continuation of the previous method, meaning that the operation is performed asynchronously. However, when the awaited operation finishes, if it represents something that throws an exception, that exception will be caught and then re-thrown within the context of your next continuation, allowing you to wrap a series of asynchronous operations in a single try/catch, having the syntax and semantics you desire. A simple example might look like:

public static async Task Foo()
{
    try
    {
        await Task.Run(() => DoSomething());
        await Task.Run(() => DoSomethingElse());
    }
    catch(Exception e)
    {
        Console.WriteLine(e);
    }
}

Here DoSomething and DoSomethingElse will be run in a thread pool thread, and if either throws an exception when running, not when being started, then the catch block will be hit.

4 Comments

There is no guarantee that DoSomething and DoSomethingElse will be executed on a separate thread. It is likely to occur with the default task scheduler but explicitly not guaranteed when using Task.Run()
@Odrade Any situation in which Run wouldn't start a new thread is almost certainly a context in which you wouldn't want it to use a new thread. Namely the only such situations are times where the current thread is also a thread pool thread, and would just end up being reclaimed if it didn't run the task synchronously, so it might as well just not get reclaimed and run the task inline. Any situation in which it would be important for Run to not run in the current thread is a situation in which it won't run in the current thread. It's not identical, true. it's superior.
@Tomasito Then you'll either need to find a way of emulating the Task model in this regard and having AsynchronousCommand catch the exception when invoking the action, and then re-throw it when the result is requested. If you cannot make such a change, or there is no mechanism whereby the caller is accessing the results (or it is not in the context you want to have your try/catch, then this isn't possible.
@Servy - I completely agree with you. I'm being pedantic because of the last sentence in your answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.