从异步方法会立即抛出抛出、法会

2023-09-04 00:30:49 作者:故旧

借助正常行为从抛出异步任务异常方法是留休眠状态,直到他们得到后观察,或直到任务得到垃圾回收。

The normal behavior for exceptions thrown from async Task methods is to stay dormant until they get observed later, or until the task gets garbage-collected.

我能想到的情况下,我可能要立即抛出。下面是一个例子:

I can think of cases where I may want to throw immediately. Here is an example:

public static async Task TestExAsync(string filename)
{
    // the file is missing, but it may be there again
    // when the exception gets observed 5 seconds later,
    // hard to debug

    if (!System.IO.File.Exists(filename))
        throw new System.IO.FileNotFoundException(filename);

    await Task.Delay(1000);
}

public static void Main()
{
    var task = TestExAsync("filename");
    try
    {
        Thread.Sleep(5000); // do other work
        task.Wait(); // wait and observe
    }
    catch (AggregateException ex)
    {
        Console.WriteLine(new { ex.InnerException.Message, task.IsCanceled });
    }
    Console.ReadLine();
}

我可以使用异步无效来解决这个问题,这立即引发:

I could use async void to get around this, which throws immediately:

// disable the "use await" warning
#pragma warning disable 1998
public static async void ThrowNow(Exception ex)
{
    throw ex;
}
#pragma warning restore 1998

public static async Task TestExAsync(string filename)
{
    if (!System.IO.File.Exists(filename))
        ThrowNow(new System.IO.FileNotFoundException(filename));

    await Task.Delay(1000);
}

现在我可以处理这个异常的权利与 Dispatcher.UnhandledException 现货或 AppDomain.CurrentDomain.UnhandledException ,至少将其带到立即用户注意。

Now I can handle this exception right on the spot with Dispatcher.UnhandledException or AppDomain.CurrentDomain.UnhandledException, at least to bring it to the user attention immediately.

是否有任何其他选项对于这种情况?是它可能是一个人为的问题?

Is there any other options for this scenario? Is it perhaps a contrived problem?

推荐答案

如果你真的想这样做,你可以用同样的方法乔恩斯基特在他的LINQ 的重新实现使用:创建一个可以引发或调用真正的异步方法同步方法:

If you really want to do this, you can use the same approach Jon Skeet used in his reimplementation of LINQ: create a synchronous method that can throw or call the real asynchronous method:

public static Task TestExAsync(string filename)
{
    if (!System.IO.File.Exists(filename))
        throw new System.IO.FileNotFoundException(filename);

    return TestExAsyncImpl(filename);
}

private static async Task TestExAsyncImpl(string filename)
{
    await Task.Delay(1000);
}

请记住,我认为这是正常的假设,一个工作返回方法不直接扔掉。例如,你可以使用 Task.WhenAll()来得到在正常情况下的一些操作所有的异常,但当异常立即抛出这个办法是行不通的。

Keep in mind that I think that it's normal to assume that a Task returning method doesn't throw directly. For example, you can use Task.WhenAll() to get all exceptions from several operations under normal circumstances, but this approach won't work when the exception is thrown immediately.