【问题标题】:Handling UnobservedTaskException处理 UnobservedTaskException
【发布时间】:2017-10-13 11:20:04
【问题描述】:

我有一个应用程序被配置为捕获任何未观察到的任务异常,在 app.config 中启用 ThrowUnobservedTaskExceptions="true"。

我有一个库类(Class1),它需要在它的构造函数中启动一个异步任务,但在某些情况下会引发异常,并且当 Class1 的实例被释放时我会遇到 UnobservedTaskException 错误(因为该任务从未等待)。

我通过在构造函数中的任务上附加 ContinueWith 并在 TaskContinuationOptions 设置为 OnlyOnFaulted 的情况下处理异常(通过访问任务的 Exception 属性)来解决此问题,并且效果很好。

现在我遇到的问题是,这个异步任务(我在构造函数中初始化)也在这个类的方法中等待作为验证检查,以确保在继续执行方法中的其余代码之前完成任务。如果我在实例化我的类(Class1)之后调用了这个方法并且如果它抛出一个错误,我附加的 ContinueWith 将被执行并处理异常。我不想要这种行为。如果在方法中等待时导致错误,我希望它抛出异常。

我只希望仅针对这种情况处理未观察到的任务异常(而不是针对整个应用程序)——当 Class1 被初始化并且没有调用任何方法并且如果任务抛出异常时,我会在 ContinueWith 中处理它。我不希望在方法中等待此任务并且如果抛出异常时执行 ContinueWith 中的代码。

这里的代码将提供更清晰的信息。请让我知道是否有办法实现这一目标。

程序.cs

using (Class1 c = new Class1())
{
       c.ValidateInitializeAsync().Wait(); // I want this to throw. Only if this line is commented, I want the exception to be handled.
}

// The application needs to be run in Release mode in order for GC to dispose c and enter into the scenario I want
while (true)
{
    Thread.Sleep(100);
    GC.Collect();
    GC.WaitForPendingFinalizers();
 }

Class1.cs

class Class1 : IDisposable
{
    public Task initializeTask;

    public Class1()
    {

        this.initializeTask = TaskHelper.InlineIfPossible(() => RunTask()).ContinueWith(t =>
        {
            Console.WriteLine(string.Format("Exception handled, {0}", t.Exception.HResult));

        }, TaskContinuationOptions.OnlyOnFaulted);
    }

    public async Task ValidateInitializeAsync()
    {
        await this.initializeTask;
    }
    public async Task RunTask()
    {
        await Task.Run(() =>
        {
            Console.WriteLine("Running task...");
            Task.Delay(5000).Wait();
            throw new InvalidOperationException("exception occured");
        });
    }

    public void Dispose()
    {
        Console.WriteLine("Class1 disposed.");
    }
}

static class TaskHelper
{
    static public Task InlineIfPossible(Func<Task> function)
    {
        if (SynchronizationContext.Current == null)
        {
            return function();
        }
        else
        {
            return Task.Run(function);
        }
    }
}

【问题讨论】:

    标签: c# .net asynchronous task continuations


    【解决方案1】:

    你所要求的是不可能的。随着时间的推移想一想:当RunTask 以异常结束时,代码必须知道当时是否要处理该异常。它无法展望未来并确定它是否由更上层堆栈的await 处理。

    我建议使用async factory pattern,以便在调用代码甚至获取实例之前立即传播任何初始化异常。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-03
      • 1970-01-01
      • 2019-02-14
      • 2016-02-15
      • 1970-01-01
      • 2015-05-13
      • 1970-01-01
      • 2020-01-06
      相关资源
      最近更新 更多