即将到来的C#8 IAsyncEnumerable
的设计使用ValueTask
和ValueTask<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
首先是有问题的。>
答案 0 :(得分:1)
阻塞直到完成Task
或Task<T>
的常见方法是调用Task.Wait()
method。
如果引发异常,它将是System.AggregatedException
。 InnerExceptions
property将具有导致当前异常的异常集合。
从.NET Framework 4.5和.NET Core 1.0开始,还有GetAwaiter()
method,您可以在其返回值上调用GetResult()
,并将抛出集合中的第一个异常。
但是您绝对不能这样做!
您应该这样做:
// this has to work in a non-async method
try {
var x = await valueTask;
} catch (Exception ex) {
// work with the exception
}
ValueTask
和ValueTask<T>
用于在可能已经有结果的情况下避免堆分配。这并不意味着安全地阻止该任务。
答案 1 :(得分:1)
corefx team的响应表明,这确实是不可能直接实现的,并且由于需要更改同伴界面而无法轻松添加,这会带来很多麻烦。
如我最初所猜测的,该解决方法建议使用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
}
答案 2 :(得分:-2)
您最好的选择是使用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'...
}
}
}