简体   繁体   English

立即从异步方法投掷

[英]Throwing immediately from async method

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. async Task方法抛出的异常的正常行为是保持休眠状态,直到稍后观察它们,或者直到任务被垃圾收集。

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: 我可以使用async void绕过它,它会立即抛出:

// 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);
}

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. 现在我可以使用Dispatcher.UnhandledExceptionAppDomain.CurrentDomain.UnhandledException立即处理此异常,至少立即引起用户注意。

Is there any other options for this scenario? 这种情况还有其他选择吗? Is it perhaps a contrived problem? 这可能是一个人为的问题吗?

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: 如果你真的想这样做,你可以使用Jon Skeet 在他重新实现LINQ时使用的相同方法:创建一个可以抛出或调用真正的异步方法的同步方法:

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);
}

Keep in mind that I think that it's normal to assume that a Task returning method doesn't throw directly. 请记住,我认为假设Task返回方法不直接抛出是正常的。 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. 例如,您可以使用Task.WhenAll()在正常情况下从多个操作中获取所有异常,但是当立即抛出异常时,此方法将不起作用。

I think the normal behavior is appropriate. 我认为正常行为是恰当的。 Your thread depends on the result of the async function to do its next processing, so the exception should be thrown on your thread. 你的线程依赖于 async函数的结果来进行下一次处理,因此应该在你的线程上抛出异常。 Your thread code could then take appropriate measure to recover from the exception. 然后,您的线程代码可以采取适当的措施从异常中恢复。 Because you could pass your Tasks around and initiate many Tasks, your recovery code could be in somewhere else where you need to get the Task result than your original called code. 因为您可以传递任务并启动许多任务,所以您的恢复代码可能位于您需要获取Task结果的其他位置,而不是原始调用代码。 If the exception is thrown immediately, it could be thrown outside your recovery code. 如果立即抛出异常,则可能会将其抛出恢复代码之外

The asynch void function throws immediately which makes sense because nothing depends on its result and there is no Task to pass around. asynch void函数立即抛出,这是有道理的,因为没有任何东西取决于它的结果,并且没有任务传递。

BTW, the point of exception handling is to recover the application state from exceptions, should not catch any exceptions that you cannot recover . 顺便说一下,异常处理的重点是从异常中恢复应用程序状态, 不应该捕获任何无法恢复的异常 When an exception is thrown, your application state may be corrupted, trying to continue working with corrupted applications cause more problems and security vulnerabilities. 抛出异常时,您的应用程序状态可能已损坏,尝试继续使用损坏的应用程序会导致更多问题和安全漏洞。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM