繁体   English   中英

如何获取ValueTask的异常?

[英]How to retrieve the Exception of a ValueTask?

即将到来的C#8 IAsyncEnumerable的设计使用ValueTaskValueTask<T>将潜在的同步结果传达回使用者逻辑。 它们都具有IsFaulted属性,但与Task不同的是,没有Exception属性。

甚至有可能没有一个ValueTask不持有正常Task并处于故障或取消状态?

ValueTask<T>.Result的文档表明,对失败的任务进行调用将重新引发所包含的Exception 因此,以下代码可以提取Exception吗?

IAsyncEnumerable<int> asyncSequence = ...

ValueTask<bool> valueTask = asyncSequence.MoveNextAsync();

if (valueTask.IsFaulted) {
    // this has to work in a non-async method
    // there is no reason to block here or use the
    // async keyword
    try {
        var x = valueTask.Result;
    } catch (Exception ex) {
        // work with the exception
    }
}

ValueTask endTask = asyncSequence.DisposeAsync();

if (endTask.IsFaulted) {
    // there is no ValueTask.Result property
    // so the appoach above can't work
}

非通用ValueTask没有Result属性。 那我该如何提取Exception呢?

通常,我认为应用AsTask可以用于两种提取,但是,据我了解,我认为它会导致分配,使得ValueTask的使用ValueTask存在问题。

阻塞直到TaskTask<T>完成的常见方法是调用Task.Wait()方法

如果引发异常,它将是System.AggregatedException InnerExceptions属性将包含导致当前异常的异常的集合。

从.NET Framework 4.5和.NET Core 1.0开始,还有GetAwaiter()方法 ,您可以在该方法上对其返回值调用GetResult()并将抛出集合中的第一个异常。

但是你永远都不要那样做!!!

你应该做这个:

// this has to work in a non-async method
try {
    var x = await valueTask;
} catch (Exception ex) {
    // work with the exception
}

如果可能已经有结果可用,则使用ValueTaskValueTask<T>避免堆分配。 这并不意味着阻止该任务是安全的。

corefx团队的回复表明,这确实是不可能直接实现的,并且由于需要更改同伴界面而无法轻松添加,这会带来很多麻烦。

正如我最初猜测的那样,该解决方法建议使用AsTask获取Exception

IAsyncEnumerable<int> asyncSequence = ...

ValueTask<bool> valueTask = asyncSequence.MoveNextAsync();

if (valueTask.IsFaulted) {
    var ex = valueTask.AsTask().Exception;
    // work with the exception
}

ValueTask endTask = asyncSequence.DisposeAsync();

if (endTask.IsFaulted) {
    var ex = valueTask.AsTask().Exception;
    // work with the exception
}

最好的选择是使用try语句并尝试在其中捕获异常,然后在以后处理它。关于不执行常规任务的ValueTask,我认为您可以使用lambda方法来解决这个问题。

try {
    var x = Task.Run(()=>{ ... });
}
catch (Exception ex) {
    // Do something with exception.
}

或适用于ValueTask的任何情况。 考虑到C#在过去的这些构建中很多时间都专注于异步任务,因此可以肯定地说,您将使用lambda和事件调用。

private void foo(ValueTask task) {
        lock (threadObj) {
            var x = Task.Run(()=> { return task.doWork(); }
            if (x == true) {
                // then do other work...
            }
            else {
                // handle 'exception'...
            }
        }
}

暂无
暂无

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

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