This example "fails":
static async void Main(string[] args)
{
try
{
await TaskEx.Run(() => { throw new Exception("failure"); });
}
catch (Exception)
{
throw new Exception("success");
}
}
That is, the exception with the text "failure" bubbles up.
Then I tried this workaround:
static async void Main(s开发者_如何学JAVAtring[] args)
{
try
{
await SafeRun(() => { throw new Exception("failure"); });
}
catch (Exception)
{
throw new Exception("success");
}
}
static async Task SafeRun(Action action)
{
var ex = default(Exception);
await TaskEx.Run(() =>
{
try
{
action();
}
catch (Exception _)
{
ex = _;
}
});
if (ex != default(Exception))
throw ex;
}
That didn't help either.
I suppose my Async CTP refresh installation could be hosed.
Should this code work as I expect ("success" bubbles up, not "failure"), or is this not "supposed" to work that way. And if not, how would you work around it?
The behavior you are seeing is likely an edge case bug or may even be correct, if unintuitive. Normally when you invoke an async method synchronously, it wraps a task around to execute and since there is no one waiting on the task to finish, the exception never makes it to the main thread. If you were to call Main directly it would succeed, but then your runtime would see an exception of "success" on another thread.
Since main is the entrypoint of your application, it is invoked synchronously and likely as the entrypoint doesn't trigger the Task wrapping behavior, so that await isn't run properly and the TaskEx.Run throws on its own thread, which shows up in the runtime as an exception being thrown on another thread.
If you were to run main as an async
method, i.e. returning a Task
(since an async
that returns void
can only really be called via await
) and blocking on it from your synchronous main context, you would get the appropriate behavior as the below test illustrates:
static async Task Main() {
try {
await TaskEx.Run(() => { throw new Exception("failure"); });
} catch(Exception) {
throw new Exception("success");
}
}
static async Task Main2() {
await Main();
}
[Test]
public void CallViaAwait() {
var t = Main2();
try {
t.Wait();
Assert.Fail("didn't throw");
} catch(AggregateException e) {
Assert.AreEqual("success",e.InnerException.Message);
}
}
[Test]
public void CallDirectly() {
var t = Main();
try {
t.Wait();
Assert.Fail("didn't throw");
} catch(AggregateException e) {
Assert.AreEqual("success", e.InnerException.Message);
}
}
I.e. the Task faults with an AggregateException
which contains the success exception as it's inner exception.
精彩评论